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

Describe note discovery note tags #713

Merged
merged 6 commits into from
May 30, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 38 additions & 15 deletions docs/architecture/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
comments: true
---

Two of Miden's key goals are parallel transaction execution and privacy.
Two of Miden's key goals are parallel transaction execution and privacy.

Polygon Miden implements a hybrid UTXO and account-based [state model](state.md) which enforces these goals with notes. Notes interact with, and transfer assets between, accounts. They can be consumed and produced asynchronously and privately.
Polygon Miden implements a hybrid UTXO and account-based [state model](state.md) which enforces these goals with notes. Notes interact with, and transfer assets between, accounts. They can be consumed and produced asynchronously and privately.

The concept of notes is a key divergence from Ethereum’s account-based model.
The concept of notes is a key divergence from Ethereum’s account-based model.

## Note design

Expand All @@ -23,11 +23,11 @@ The concept of notes is a key divergence from Ethereum’s account-based model.

## Note lifecycle

New notes are created by executing transactions.
New notes are created by executing transactions.

After verifying the transaction proof the operator adds either only the note hash (private notes) or the full note data (public notes) to the note database.
After verifying the transaction proof the operator adds either only the note hash (private notes) or the full note data (public notes) to the note database.

Notes can be produced and consumed locally by users in local transactions or by the operator in a network transaction.
Notes can be produced and consumed locally by users in local transactions or by the operator in a network transaction.

Note consumption requires the transacting party to know the note data to compute the nullifier. After successful verification, the operator sets the corresponding entry in the nullifier database to "consumed".

Expand All @@ -52,11 +52,10 @@ There are [standard note scripts](https://github.com/0xPolygonMiden/miden-base/t
* P2ID and P2IDR scripts are used to send assets to a specific account ID. The scripts check at note consumption if the executing account ID equals the account ID that was set by the note creator as note inputs. The P2IDR script is reclaimable and thus after a certain block height can also be consumed by the sender itself.
* SWAP script is a simple way to swap assets. It adds an asset from the note into the consumer's vault and creates a new note consumable by the first note's issuer containing the requested asset.

!!! info "Example note script pay to ID (P2ID)"
Want to know how to ensure a note can only be consumed by a specified account?</
??? note "Example note script pay to ID (P2ID)"

#### Goal of the P2ID script

The P2ID script defines a specific target account ID as the only account that can consume the note. Such notes ensure a targeted asset transfer.

#### Imports and context
Expand Down Expand Up @@ -121,9 +120,9 @@ There are [standard note scripts](https://github.com/0xPolygonMiden/miden-base/t
1. Every note script starts with the note script root on top of the stack.
2. After the `dropw`, the stack is cleared.
3. Next, the script stored the note inputs at pos 0 in the [relative note context memory](https://0xpolygonmiden.github.io/miden-base/transactions/transaction-procedures.html#transaction-contexts) by `push.0 exec.note::get_inputs`.
4. Then, `mem_load` loads a `Felt` from the specified memory address and puts it on top of the stack, in that cases the `target_account_id` defined by the creator of the note.
4. Then, `mem_load` loads a `Felt` from the specified memory address and puts it on top of the stack, in that cases the `target_account_id` defined by the creator of the note.
5. Now, the note invokes `get_id` from the account API using `exec.account::get_id` - which is possible even in the note context.

Because, there are two account IDs on top of the stack now, `assert_eq` fails if the two account IDs (target_account_id and executing_account_id) are not the same. That means, the script cannot be successfully executed if executed by any other account than the account specified by the note creator using the note inputs.

If execution hasn't failed, the script invokes a helper procedure `exec.add_note_assets_to_account` to add the note's assets into the executing account's vault.
Expand Down Expand Up @@ -185,7 +184,7 @@ There are [standard note scripts](https://github.com/0xPolygonMiden/miden-base/t

## Note storage mode

Similar to accounts, there are two storage modes for notes in Miden. Notes can be stored on-chain in the [note database](https://0xpolygonmiden.github.io/miden-base/architecture/state.html#notes-database) with all data publicly visible for everyone. Alternatively, notes can be stored off-chain by committing only the note hash to the note database.
Similar to accounts, there are two storage modes for notes in Miden - private and public. Notes can be stored publicly in the [note database](https://0xpolygonmiden.github.io/miden-base/architecture/state.html#notes-database) with all data publicly visible for everyone. Alternatively, notes can be stored privately by committing only the note hash to the note database.

Every note has a unique note hash. It is defined as follows:

Expand All @@ -196,10 +195,34 @@ hash(hash(hash(hash(serial_num, [0; 4]), script_hash), input_hash), vault_hash)
!!! info
To compute a note's hash, we do not need to know the note's `serial_num`. Knowing the hash of the `serial_num` (as well as `script_hash`, `input_hash` and `note_vault`) is also sufficient. We compute the hash of `serial_num` as `hash(serial_num, [0; 4])` to simplify processing within the VM._

## Note discovery
## Note discovery (note tags)
Copy link
Contributor

@bobbinth bobbinth May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think one thing missing from this section is a concrete example of how note tag can be used by one user to make a note discoverable by another user. I think after reading this, people may still not fully understand how tags can be used and an example could drive it home. We could use a P2ID note tag scheme to explain this.

In general, I think we can make this section much more detailed (the content here could be easily 3x - 4x of what is here now) and it could maybe even be its own separate sub-section. But maybe that's for another PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jup, I also have the feeling that the entire note chapter is too long already. I will add the example for now and we should do a bigger refactor for the chapter and add several sub-sections.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I think, what is missing to make those really great docs:

  • the ppl who write / design the code should also write the section (they know exactly why a certain design was chosen)
  • Miden cannot be used at the moment, but the docs should describe how to use Miden. It will get better, once there is the compiler. Then we can describe how to use a note tag using a specific example.


Note discovery describes the process by which Miden clients find notes they want to consume. Miden clients can query the Miden node for notes carrying a certain note tag. Note tags are best-effort filters for notes registered on the network. They are lightweight values used to speed up queries. Clients can follow tags for specific use cases, such as swap scripts, or agree with a group of users on certain tags for their specific needs. Tags are also used by the operator to identify notes intended for network execution and include the corresponding information on how to execute them.

```arduino
0b009f4adc47857e2f6
```

The example note tag above indicates that the network operator (Miden node) executes the note against the account with the ID `0x09f4adc47857e2f6`. In this case, the note and the account against which it gets executed must be `public`.

The two most signification bits of the note tag have the following interpretation:

| Prefix | Execution hint | Target | Allowed note type |
| ------ | :------------: | :------: | :----------------:|
| `0b00` | Network | Specific | NoteType::Public |
| `0b01` | Network | Use case | NoteType::Public |
| `0b10` | Local | Any | NoteType::Public |
| `0b11` | Local | Any | Any |

- Where:

- Execution Hint: Set to `Network` for network transactions. These notes will be further validated and, if possible, consumed in a network transaction.
- Target: Describes how to further interpret the bits in the note tag. For tags with a specific target, the rest of the tag is interpreted as an `account_id`. For use case values, the meaning of the rest of the tag is not specified by the protocol and can be used by applications built on top of the rollup.
- Note type describes the note's storage mode, either `public` or `private`.

The following 30 bits can represent anything—from Account IDs to use cases or any custom logic agreed upon.

Note discovery describes the process of Miden clients finding notes they want to consume. There are two ways to receive new relevant notes - getting notes via an off-chain channel or querying the Miden operator to request newly recorded relevant notes.
The latter is done via note tags. Tags are part of the note's metadata and are represented by a `Felt`. The `SyncState` API of the Miden node requires the Miden client to provide a `note_tag` value which is used as a filter in the operator's response. Tags are useful for note discovery enabling an easy collection of all notes matching a certain tag.
Using note tags is a compromise between privacy and latency. If a user queries the operator using the note ID, the operator learns which note a specific user is interested in. Alternatively, if a user always downloads all registered notes and filters locally, it is quite inefficient. By using tags, users can customize privacy parameters by narrowing or broadening their note tag schemes.

## Note consumption

Expand Down
Loading