-
Notifications
You must be signed in to change notification settings - Fork 132
Move NullifierTree and BlockChain from node
#1304
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
Merged
Merged
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
51fecb2
feat: Only iterate if num leaves is different in account tree
PhilippGackstatter 862eda2
chore: Add changelog entry
PhilippGackstatter 7fdff8a
chore: Remove period from duplicate error message
PhilippGackstatter fe79ffe
Merge remote-tracking branch 'origin/next' into pgackst-account-tree-…
PhilippGackstatter 29ce0ac
feat: Guarantee account ID prefix uniqueness in mutation set
PhilippGackstatter 45d93f0
chore: Fix changelog
PhilippGackstatter 8a8433d
feat: Add `NullifierTree` with tests
PhilippGackstatter 3916599
feat: Add `BlockChain`
PhilippGackstatter 66730b0
feat: Use `BlockChain` in `MockChain`
PhilippGackstatter 6e74d3c
feat: Use `NullifierTree` in `MockChain`
PhilippGackstatter 950d82c
chore: Add changelog entry
PhilippGackstatter ee04688
fix: changelog entry
PhilippGackstatter cb3337e
Merge branch 'next' into pgackst-nullifier-tree-blockchain
bobbinth e315e93
chore: Address review comments
PhilippGackstatter ff94435
chore: Add tests separator
PhilippGackstatter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| use alloc::collections::BTreeSet; | ||
|
|
||
| use miden_crypto::merkle::{Mmr, MmrError, MmrPeaks, MmrProof, PartialMmr}; | ||
|
|
||
| use crate::{Digest, block::BlockNumber}; | ||
|
|
||
| /// The [Merkle Mountain Range](Mmr) defining the Miden blockchain. | ||
| /// | ||
| /// The values of the leaves in the MMR are the commitments of blocks, i.e. | ||
| /// [`BlockHeader::commitment`](crate::block::BlockHeader::commitment). | ||
| /// | ||
| /// Each new block updates the blockchain by adding **the previous block's commitment** to the MMR. | ||
| /// This means the chain commitment found in block 10's header commits to all blocks 0..=9, but not | ||
| /// 10 itself. This results from the fact that block 10 cannot compute its own block commitment | ||
| /// and thus cannot add itself to the chain. Hence, the blockchain MMR is lagging behind by one | ||
| /// block. | ||
| /// | ||
| /// Some APIs take a _state block_ which is equivalent to the concept of _forest_ of the underlying | ||
| /// MMR. As an example, if the blockchain has 20 blocks in total, and the state block is 10, then | ||
| /// the API works in the context of the chain at the time it had 10 blocks, i.e. it contains blocks | ||
| /// 0..=9. This is useful, for example, to retrieve proofs that are valid when verified against the | ||
| /// chain commitment of block 10. | ||
| /// | ||
| /// The maximum number of supported blocks is [`u32::MAX`]. This is not validated however. | ||
| #[derive(Debug, Clone)] | ||
| pub struct BlockChain { | ||
| mmr: Mmr, | ||
| } | ||
|
|
||
| impl BlockChain { | ||
| // CONSTRUCTORS | ||
| // -------------------------------------------------------------------------------------------- | ||
|
|
||
| /// Returns a new, empty blockchain. | ||
| pub fn new() -> Self { | ||
| Self { mmr: Mmr::new() } | ||
| } | ||
|
|
||
| /// Construct a new blockchain from an [`Mmr`] without validation. | ||
| pub fn from_mmr_unchecked(mmr: Mmr) -> Self { | ||
| Self { mmr } | ||
| } | ||
|
|
||
| // PUBLIC ACCESSORS | ||
| // -------------------------------------------------------------------------------------------- | ||
|
|
||
| /// Returns the number of blocks in the chain. | ||
| pub fn num_blocks(&self) -> u32 { | ||
| // SAFETY: The chain should never contain more than u32::MAX blocks, so a non-panicking cast | ||
| // should be fine. | ||
| self.mmr.forest() as u32 | ||
| } | ||
|
|
||
| /// Returns the tip of the chain, i.e. the number of the latest block in the chain, unless the | ||
| /// chain is empty. | ||
| pub fn chain_tip(&self) -> Option<BlockNumber> { | ||
| if self.num_blocks() == 0 { | ||
| return None; | ||
| } | ||
|
|
||
| Some(BlockNumber::from(self.num_blocks() - 1)) | ||
| } | ||
|
|
||
| /// Returns the current peaks of the MMR. | ||
| pub fn peaks(&self) -> MmrPeaks { | ||
| self.mmr.peaks() | ||
| } | ||
|
|
||
| /// Returns the peaks of the chain at the state of the given block. | ||
| /// | ||
| /// Note that this represents the state of the chain where the block at the given number **is | ||
| /// not yet** in the chain. For example, if the given block number is 5, then the returned peaks | ||
| /// represent the chain whose latest block is 4. See the type-level documentation for why this | ||
| /// is the case. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if the specified `block` exceeds the number of blocks in the chain. | ||
| pub fn peaks_at(&self, state_block: BlockNumber) -> Result<MmrPeaks, MmrError> { | ||
|
PhilippGackstatter marked this conversation as resolved.
Outdated
|
||
| self.mmr.peaks_at(state_block.as_usize()) | ||
| } | ||
|
|
||
| /// Returns an [`MmrProof`] for the `block` with the given number. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if: | ||
| /// - The specified block number does not exist in the chain. | ||
| pub fn open(&self, block: BlockNumber) -> Result<MmrProof, MmrError> { | ||
| self.mmr.open(block.as_usize()) | ||
| } | ||
|
|
||
| /// Returns an [`MmrProof`] for the `block` with the given number at the state of the given | ||
| /// `state_block`. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if: | ||
| /// - The specified block number does not exist in the chain. | ||
| /// - The specified state block number exceeds the number of blocks in the chain. | ||
| pub fn open_at( | ||
| &self, | ||
| block: BlockNumber, | ||
| state_block: BlockNumber, | ||
| ) -> Result<MmrProof, MmrError> { | ||
|
PhilippGackstatter marked this conversation as resolved.
|
||
| self.mmr.open_at(block.as_usize(), state_block.as_usize()) | ||
| } | ||
|
|
||
| /// Returns a reference to the underlying [`Mmr`]. | ||
| pub fn as_mmr(&self) -> &Mmr { | ||
| &self.mmr | ||
| } | ||
|
|
||
| /// Creates a [`PartialMmr`] at the state of the given block. This means the hashed peaks of the | ||
| /// returned partial MMR will match the state block's chain commitment. This MMR will include | ||
| /// authentication paths for all blocks in the provided `blocks` set. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if: | ||
| /// - the specified `latest_block_number` exceeds the number of blocks in the chain. | ||
| /// - any block in `blocks` is not in the state of the chain specified by `latest_block_number`. | ||
| pub fn partial_mmr_from_blocks( | ||
| &self, | ||
| blocks: &BTreeSet<BlockNumber>, | ||
| state_block: BlockNumber, | ||
| ) -> Result<PartialMmr, MmrError> { | ||
| // Using latest block as the target state means we take the state of the MMR one before | ||
| // the latest block. | ||
| let peaks = self.peaks_at(state_block)?; | ||
|
|
||
| // Track the merkle paths of the requested blocks in the partial MMR. | ||
| let mut partial_mmr = PartialMmr::from_peaks(peaks); | ||
| for block_num in blocks.iter() { | ||
| let leaf = self.mmr.get(block_num.as_usize())?; | ||
| let path = self.open_at(*block_num, state_block)?.merkle_path; | ||
|
|
||
| // SAFETY: We should be able to fill the partial MMR with data from the chain MMR | ||
| // without errors, otherwise it indicates the blockchain is invalid. | ||
| partial_mmr | ||
| .track(block_num.as_usize(), leaf, &path) | ||
| .expect("filling partial mmr with data from mmr should succeed"); | ||
| } | ||
|
|
||
| Ok(partial_mmr) | ||
| } | ||
|
|
||
| // PUBLIC MUTATORS | ||
| // -------------------------------------------------------------------------------------------- | ||
|
|
||
| /// Adds a block commitment to the MMR. | ||
| /// | ||
| /// The caller must ensure that this commitent is the one for the next block in the chain. | ||
| pub fn push(&mut self, block_commitment: Digest) { | ||
| self.mmr.add(block_commitment); | ||
| } | ||
| } | ||
|
|
||
| impl Default for BlockChain { | ||
| fn default() -> Self { | ||
| Self::new() | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.