From a8d038cf4ad461033a7db6295873ea092b171975 Mon Sep 17 00:00:00 2001
From: Paul-Henry Kajfasz <42912740+phklive@users.noreply.github.com>
Date: Mon, 2 Dec 2024 14:43:00 +0700
Subject: [PATCH] Update docs for consolidation (#998)
* Update readme + remove tutorials from base
* Change version to 6
* Cargo update
* Update mkdocs.yml + remove images from tutorials
* Fix broken link
* Reverted cargo.lock update
---
README.md | 4 +-
docs/architecture/accounts.md | 109 +++---
docs/architecture/assets.md | 12 +-
docs/architecture/execution.md | 20 +-
docs/architecture/limits.md | 8 +-
docs/architecture/notes.md | 328 +++++++++---------
docs/architecture/overview.md | 6 +-
docs/architecture/state.md | 38 +-
docs/architecture/transactions/contexts.md | 16 +-
docs/architecture/transactions/execution.md | 20 +-
docs/architecture/transactions/kernel.md | 140 +++-----
docs/architecture/transactions/overview.md | 46 +--
docs/architecture/transactions/procedures.md | 8 +-
docs/img/get-started/account-a.png | Bin 51865 -> 0 bytes
docs/img/get-started/account-b.png | Bin 51574 -> 0 bytes
docs/img/get-started/commit-height.png | Bin 42255 -> 0 bytes
docs/img/get-started/consumed-note.png | Bin 45808 -> 0 bytes
docs/img/get-started/miden-account-list.png | Bin 37114 -> 0 bytes
docs/img/get-started/note-view.png | Bin 41685 -> 0 bytes
docs/img/get-started/processing-note.png | Bin 50643 -> 0 bytes
.../get-started/transaction-confirmation.png | Bin 143664 -> 0 bytes
docs/img/get-started/two-accounts.png | Bin 54890 -> 0 bytes
docs/img/get-started/view-account-vault.png | Bin 192391 -> 0 bytes
docs/index.md | 28 +-
.../get-started/create-account-use-faucet.md | 201 -----------
docs/introduction/get-started/p2p-private.md | 102 ------
docs/introduction/get-started/p2p-public.md | 100 ------
.../introduction/get-started/prerequisites.md | 20 --
docs/introduction/roadmap.md | 7 -
docs/network/network.md | 50 ++-
docs/roadmap.md | 1 +
mkdocs.yml | 7 +-
32 files changed, 357 insertions(+), 914 deletions(-)
delete mode 100644 docs/img/get-started/account-a.png
delete mode 100644 docs/img/get-started/account-b.png
delete mode 100644 docs/img/get-started/commit-height.png
delete mode 100644 docs/img/get-started/consumed-note.png
delete mode 100644 docs/img/get-started/miden-account-list.png
delete mode 100644 docs/img/get-started/note-view.png
delete mode 100644 docs/img/get-started/processing-note.png
delete mode 100644 docs/img/get-started/transaction-confirmation.png
delete mode 100644 docs/img/get-started/two-accounts.png
delete mode 100644 docs/img/get-started/view-account-vault.png
delete mode 100644 docs/introduction/get-started/create-account-use-faucet.md
delete mode 100644 docs/introduction/get-started/p2p-private.md
delete mode 100644 docs/introduction/get-started/p2p-public.md
delete mode 100644 docs/introduction/get-started/prerequisites.md
delete mode 100644 docs/introduction/roadmap.md
create mode 100644 docs/roadmap.md
diff --git a/README.md b/README.md
index 4d1377c50..b9f99eedd 100644
--- a/README.md
+++ b/README.md
@@ -16,10 +16,10 @@ Miden is a zero-knowledge rollup for high-throughput and private applications. M
If you want to join the technical discussion or learn more about the project, please check out
-* the [Documentation](https://docs.polygon.technology/miden/).
+* the [Documentation](https://0xpolygonmiden.github.io/miden-docs).
* the [Discord](https://discord.gg/0xpolygonrnd)
* the [Repo](https://github.com/0xPolygonMiden)
-* the [Roadmap](roadmap.md)
+* the [Roadmap](docs/roadmap.md)
## Status and features
diff --git a/docs/architecture/accounts.md b/docs/architecture/accounts.md
index f4841e598..e8b68cd9d 100644
--- a/docs/architecture/accounts.md
+++ b/docs/architecture/accounts.md
@@ -1,27 +1,23 @@
----
-comments: true
----
-
Accounts are basic building blocks representing a user or an autonomous smart contract.
-For smart contracts the go-to solution is account-based state. Miden supports expressive smart contracts via a Turing-complete language and the use of accounts.
+For smart contracts, the go-to solution is account-based state. Miden supports expressive smart contracts via a Turing-complete language and the use of accounts.
-In Miden, an account is an entity which holds assets and defines rules about how to transfer these assets.
+In Miden, an account is an entity that holds assets and defines rules about how to transfer these assets.
## Account design
-In Miden every account is a smart contract. The diagram below illustrates the basic components of an account.
+In Miden, every account is a smart contract. The diagram below illustrates the basic components of an account.
-
-![Architecture core concepts](../img/architecture/account/account-definition.png){ width="25%" }
-
+
+
+
-!!! tip "Key to diagram"
- * **Account ID**: A unique identifier for an account. This does not change throughout its lifetime.
- * **Storage**: User-defined data which can be stored in an account.
- * **Nonce**: A counter which increments whenever the account state changes.
- * **Vault**: A collection of assets stored in an account.
- * **Code**: A collection of functions which define the external interface for an account.
+> **Tip: Key to diagram**
+> - **Account ID**: A unique identifier for an account. This does not change throughout its lifetime.
+> - **Storage**: User-defined data which can be stored in an account.
+> - **Nonce**: A counter which increments whenever the account state changes.
+> - **Vault**: A collection of assets stored in an account.
+> - **Code**: A collection of functions which define the external interface for an account.
### Account ID
@@ -33,14 +29,12 @@ The four most significant bits specify the [account type](#account-types) - regu
The [storage of an account](../../objects/src/accounts/storage/mod.rs) is composed of a variable number of index-addressable [storage slots](../../objects/src/accounts/storage/slot/mod.rs), up to 255 slots in total.
-Each slot has a type which defines its size and structure. Currently, the following types are supported:
+Each slot has a type that defines its size and structure. Currently, the following types are supported:
- * `StorageSlot::Value`: contains a single `Word` of data (i.e., 32 bytes).
- * `StorageSlot::Map`: contains a [StorageMap](../../objects/src/accounts/storage/map.rs) which is a key-value map where both keys and
- values are `Word`s. The value of a storage slot containing a map is the commitment to the
- underlying map.
+* `StorageSlot::Value`: contains a single `Word` of data (i.e., 32 bytes).
+* `StorageSlot::Map`: contains a [StorageMap](../../objects/src/accounts/storage/map.rs) which is a key-value map where both keys and values are `Word`s. The value of a storage slot containing a map is the commitment to the underlying map.
-As described below, accounts can be stored off-chain (private) and on-chain (public). Accounts that store huge amounts of data, as it is possible using storage maps, are better designed as off-chain accounts.
+As described below, accounts can be stored off-chain (private) and on-chain (public). Accounts that store large amounts of data, as is possible using storage maps, are better designed as off-chain accounts.
### Nonce
@@ -54,17 +48,14 @@ An asset container for an account.
An account vault can contain an unlimited number of [assets](assets.md). The assets are stored in a sparse Merkle tree as follows:
-* For fungible assets, the index of a node is defined by the issuing faucet ID, and the value
- of the node is the asset itself. Thus, for any fungible asset there will be only one node
- in the tree.
-* For non-fungible assets, the index is defined by the asset itself, and the asset is also
- the value of the node.
+* For fungible assets, the index of a node is defined by the issuing faucet ID, and the value of the node is the asset itself. Thus, for any fungible asset, there will be only one node in the tree.
+* For non-fungible assets, the index is defined by the asset itself, and the asset is also the value of the node.
An account vault can be reduced to a single hash which is the root of the sparse Merkle tree.
### Code
-The interface for accounts. In Miden every account is a smart contract. It has an interface that exposes functions that can be called by [note scripts](notes.md#the-note-script) and transaction scripts. Users cannot call those functions directly.
+The interface for accounts. In Miden, every account is a smart contract. It has an interface that exposes functions that can be called by [note scripts](notes.md#the-note-script) and transaction scripts. Users cannot call those functions directly.
Functions exposed by the account have the following properties:
@@ -72,8 +63,8 @@ Functions exposed by the account have the following properties:
* Only account functions have [mutable access](transactions/contexts.md) to an account's storage and vault. Therefore, the only way to modify an account's internal state is through one of the account's functions.
* Account functions can take parameters and can create new notes.
-!!! note
- Since code in Miden is expressed as MAST, every function is a commitment to the underlying code. The code cannot change unnoticed to the user because its hash would change. Behind any MAST root there can only be `256` functions.
+> **Note**
+> Since code in Miden is expressed as MAST, every function is a commitment to the underlying code. The code cannot change unnoticed to the user because its hash would change. Behind any MAST root there can only be `256` functions.
#### Example account code
@@ -97,12 +88,12 @@ There is a standard for a basic user account. It exposes three functions via its
```
-[Note scripts](notes.md#the-note-script) or transaction scripts can call `receive_asset`, `create_note` and `move_asset_to_note` procedures.
+[Note scripts](notes.md#the-note-script) or transaction scripts can call `receive_asset`, `create_note`, and `move_asset_to_note` procedures.
-Transaction scripts can also call `auth_tx_rpo_falcon512` and authenticate the transaction.
+Transaction scripts can also call `auth_tx_rpo_falcon512` to authenticate the transaction.
-!!! warning
- Without correct authentication, i.e. knowing the correct private key, a note cannot successfully invoke `receive_asset`, `create_note` or `move_asset_to_note`.
+> **Warning**
+> Without correct authentication, i.e., knowing the correct private key, a note cannot successfully invoke `receive_asset`, `create_note`, or `move_asset_to_note`.
##### Basic fungible faucet (faucet for fungible assets)
@@ -128,7 +119,7 @@ There is also a standard for a [basic fungible faucet](https://github.com/0xPoly
sub
# => [max_supply - total_issuance, amount, tag, note_type, RECIPIENT, ...]
- # check that amount =< max_supply - total_issuance, fails if otherwise
+ # check that amount <= max_supply - total_issuance, fails if otherwise
dup.1 gte assert.err=ERR_BASIC_FUNGIBLE_MAX_SUPPLY_OVERFLOW
# => [asset, tag, note_type, RECIPIENT, ...]
@@ -173,48 +164,48 @@ There is also a standard for a [basic fungible faucet](https://github.com/0xPoly
The contract exposes two functions `distribute` and `burn`.
-The first function `distribute` can only be called by the faucet owner, otherwise it fails. As inputs, the function expects everything that is needed to create a note containing the freshly minted asset, i.e., amount, metadata, and recipient.
+The first function, `distribute`, can only be called by the faucet owner; otherwise, it fails. As inputs, the function expects everything that is needed to create a note containing the freshly minted asset, i.e., amount, metadata, and recipient.
-The second function `burn` burns the tokens that are contained in a note and can be called by anyone.
+The second function, `burn`, burns the tokens that are contained in a note and can be called by anyone.
-!!! info "Difference between `burn` and `distribute`"
- The `burn` procedure exposes `exec.account::incr_nonce`, so by calling `burn` the nonce of the executing account gets increased by `1` and the transaction will pass the epilogue check. The `distribute` procedure does not expose that. That means the executing user needs to call `basic::auth_tx_rpo_falcon512` which requires the private key.*
+> **Info: Difference between `burn` and `distribute`**
+> The `burn` procedure exposes `exec.account::incr_nonce`, so by calling `burn`, the nonce of the executing account gets increased by `1`, and the transaction will pass the epilogue check. The `distribute` procedure does not expose that. That means the executing user needs to call `basic::auth_tx_rpo_falcon512`, which requires the private key.
## Account creation
-For an account to exist it must be present in the [account database](state.md#account-database) kept on the Miden node(s).
+For an account to exist, it must be present in the [account database](state.md#account-database) kept on the Miden node(s).
However, new accounts can be created locally by users using the Miden client. The process is as follows:
-* Alice creates a new account ID (according to the account types) using the Miden client.
-* Alice's Miden client asks the Miden node to check if the new ID already exists.
-* Alice shares the ID with Bob (eg. when Alice wants to receive funds).
-* Bob executes a transaction and creates a note that contains an asset for Alice.
-* Alice consumes Bob's note to receive the asset in a transaction.
-* Depending on the account storage mode (private vs. public) and transaction type (local vs. network) the operator eventually receives the new account ID and - if the transaction is correct - adds the ID to the account database.
+1. Alice creates a new account ID (according to the account types) using the Miden client.
+2. Alice's Miden client asks the Miden node to check if the new ID already exists.
+3. Alice shares the ID with Bob (e.g., when Alice wants to receive funds).
+4. Bob executes a transaction and creates a note that contains an asset for Alice.
+5. Alice consumes Bob's note to receive the asset in a transaction.
+6. Depending on the account storage mode (private vs. public) and transaction type (local vs. network), the operator eventually receives the new account ID and - if the transaction is
+
+ correct - adds the ID to the account database.
A user can create an account in one of the following manners:
-1. Use the [Miden client](https://docs.polygon.technology/miden/miden-client/) as a wallet.
-2. Use the Miden base builtin functions for wallet creation: [basic wallet](https://github.com/0xPolygonMiden/miden-base/blob/4e6909bbaf65e77d7fa0333e4664be81a2f65eda/miden-lib/src/accounts/wallets/mod.rs#L15), [fungible faucet](https://github.com/0xPolygonMiden/miden-base/blob/4e6909bbaf65e77d7fa0333e4664be81a2f65eda/miden-lib/src/accounts/faucets/mod.rs#L11)
+1. Use the [Miden client](https://0xpolygonmiden.github.io/miden-docs/miden-client/index.html) as a wallet.
+2. Use the Miden base built-in functions for wallet creation: [basic wallet](https://github.com/0xPolygonMiden/miden-base/blob/4e6909bbaf65e77d7fa0333e4664be81a2f65eda/miden-lib/src/accounts/wallets/mod.rs#L15), [fungible faucet](https://github.com/0xPolygonMiden/miden-base/blob/4e6909bbaf65e77d7fa0333e4664be81a2f65eda/miden-lib/src/accounts/faucets/mod.rs#L11)
## Account types
There are two basic account types in Miden: Regular accounts and faucets. Only faucets can mint new assets. Regular accounts can be mutable or immutable, which simply means that it is possible to change the account code after creation.
-Type and mutability is encoded in the most significant bits of the account's ID.
+Type and mutability are encoded in the most significant bits of the account's ID.
-| | Basic mutable | Basic immutable | Fungible faucet | Non-fungible faucet |
-|---|---|---|---|---|
-| **Description** | For most users, e.g. a wallet. Code changes allowed, including public API. | For most smart contracts. Once deployed code is immutable. | Users can issue fungible assets and customize them. | Users can issue non-fungible assets and customize them. |
-| **Code updatability** | yes | no | no | no |
-| **Most significant bits** | `00` | `01` | `10` | `11` |
+| | Basic mutable | Basic immutable | Fungible faucet | Non-fungible faucet |
+|------------------------|---------------|------------------|------------------|----------------------|
+| **Description** | For most users, e.g., a wallet. Code changes allowed, including public API. | For most smart contracts. Once deployed, code is immutable. | Users can issue fungible assets and customize them. | Users can issue non-fungible assets and customize them. |
+| **Code updatability** | Yes | No | No | No |
+| **Most significant bits** | `00` | `01` | `10` | `11` |
## Public and private accounts
-Users can decide whether to keep their accounts private or public at account creation. The account ID encodes this preference on the third and fourth most significant bit.
-
-* Accounts with public state: The actual state is stored on-chain. This is similar to how accounts work in public blockchains, like Ethereum. Smart contracts that depend on public shared state should be stored public on Miden, e.g., DEX contract.
-* Accounts with private state: Only the hash of the account is stored on-chain. Users who want to stay private, and manage their own data, should choose this option. Users who want to interact with private accounts need to know the account's interface.
+Users can decide whether to keep their accounts private or public at account creation. The account ID encodes this preference in the third and fourth most significant bits.
-
+* **Accounts with public state**: The actual state is stored on-chain. This is similar to how accounts work in public blockchains, like Ethereum. Smart contracts that depend on public shared state should be stored publicly on Miden, e.g., a DEX contract.
+* **Accounts with private state**: Only the hash of the account is stored on-chain. Users who want to stay private and manage their own data should choose this option. Users who want to interact with private accounts need to know the account's interface.
diff --git a/docs/architecture/assets.md b/docs/architecture/assets.md
index d01981d71..d9e19e92e 100644
--- a/docs/architecture/assets.md
+++ b/docs/architecture/assets.md
@@ -1,7 +1,3 @@
----
-comments: true
----
-
In Miden, users can create and trade arbitrary fungible and non-fungible assets.
We differentiate between native and non-native assets in Miden. Native assets follow the Miden asset model. Non-native assets are all other data structures of value that can be exchanged.
@@ -29,13 +25,11 @@ The `faucet_id` identifies the faucet and starts with a different sequence depen
Faucets can create assets and immediately distribute them by producing notes. However, assets can also stay in the faucet after creation to be sent later, e.g., in a bundle. That way, one can mint a million NFTs locally in a single transaction and then send them out as needed in separate transactions in the future.
-
![Architecture core concepts](../img/architecture/asset/asset-issuance.png)
-
### Fungible assets
-A fungible asset is encoded using the amount and the `faucet_id` of the faucet which issued the asset. The amount is guaranteed to be `$2^{63} - 1$` or smaller, the maximum supply for any fungible asset. Examples of fungible assets are ETH and stablecoins, e.g., DAI, USDT, and USDC.
+A fungible asset is encoded using the amount and the `faucet_id` of the faucet which issued the asset. The amount is guaranteed to be `$2^{63} - 1$ or smaller, the maximum supply for any fungible asset. Examples of fungible assets are ETH and stablecoins, e.g., DAI, USDT, and USDC.
If the `faucet_id` of MATIC is `2`, 100 MATIC are encoded as `[100, 0, 0, 2]`; the `0`s in the middle distinguish between fungible and non-fungible assets.
@@ -49,9 +43,7 @@ Examples of non-fungible assets are all NFTs, e.g., a DevCon ticket. The ticket'
[Accounts](accounts.md) and [notes](notes.md) contain asset vaults that are used to store assets. Accounts can keep unlimited assets in a sparse Merkle tree called `account vault`. Notes can store up to `255` distinct assets.
-
![Architecture core concepts](../img/architecture/asset/asset-storage.png)
-
The information on which and how many assets are owned can be private depending on the account's or note's storage mode. This is true for any native asset in Miden.
@@ -63,4 +55,4 @@ For example, developers can replicate the Ethereum ERC20 model, where ownership
Furthermore, a complete account can be treated as a programmable asset because ownership of accounts is transferrable. An account could be a "crypto kitty" with specific attributes and rules, and people can trade these "crypto kitties" by transferring accounts between each other.
-We can also think of an account representing a car. The owner of the car can change so the car account - granting access to the physical car - can be treated as an asset. In this car account, there could be rules defining who is allowed to drive the car and when.
\ No newline at end of file
+We can also think of an account representing a car. The owner of the car can change so the car account - granting access to the physical car - can be treated as an asset. In this car account, there could be rules defining who is allowed to drive the car and when.
diff --git a/docs/architecture/execution.md b/docs/architecture/execution.md
index 56efd9c45..520501399 100644
--- a/docs/architecture/execution.md
+++ b/docs/architecture/execution.md
@@ -1,14 +1,8 @@
----
-comments: true
----
-
Polygon Miden is an Ethereum Rollup. It batches transactions - or more precisely, proofs - that occur in the same time period into a block.
The Miden execution model describes how state progresses on an individual level via transactions and at the global level expressed as aggregated state updates in blocks.
-
![Architecture core concepts](../img/architecture/execution/execution.png)
-
## Transaction execution
@@ -36,14 +30,12 @@ Batch proofs are aggregated into blocks by the Miden node. The blocks are then s
A block produced by the Miden node looks something like this:
-
-![Architecture core concepts](../img/architecture/execution/block.png){ width="80%" }
-
+![Architecture core concepts](../img/architecture/execution/block.png)
-!!! tip "Block contents"
- * **state updates** only contain the hashes of changes. For example, for each updated account, we record a tuple `([account id], [new account hash])`.
- * **ZK Proof** attests that, given a state commitment from the previous block, there was a sequence of valid transactions executed that resulted in the new state commitment, and the output also included state updates.
- * The block also contains full account and note data for public accounts and notes. For example, if account `123` is an updated public account which, in the **state updates** section we'd see a records for it as `(123, 0x456..)`. The full new state of this account (which should hash to `0x456..`) would be included in a separate section.
+> **Tip: Block contents**
+> - **State updates** only contain the hashes of changes. For example, for each updated account, we record a tuple `([account id], [new account hash])`.
+> - **ZK Proof** attests that, given a state commitment from the previous block, there was a sequence of valid transactions executed that resulted in the new state commitment, and the output also included state updates.
+> - The block also contains full account and note data for public accounts and notes. For example, if account `123` is an updated public account which, in the **state updates** section we'd see a records for it as `(123, 0x456..)`. The full new state of this account (which should hash to `0x456..`) would be included in a separate section.
### Verifying valid block state
@@ -69,4 +61,4 @@ The new node would need to do the following:
3. Download the current states of account, note, and nullifier databases.
4. Verify that the downloaded current state matches the state commitment in the latest block.
-Overall, state sync is dominated by the time needed to download the data.
\ No newline at end of file
+Overall, state sync is dominated by the time needed to download the data.
diff --git a/docs/architecture/limits.md b/docs/architecture/limits.md
index 51933af81..b0b102ecc 100644
--- a/docs/architecture/limits.md
+++ b/docs/architecture/limits.md
@@ -6,21 +6,21 @@ The following are the current limits enforced in the `miden-base` and `miden-nod
- Max assets per account: **no limit**.
- Max top-level storage slots per account: **255**. Each storage slot can contain an unlimited
amount of data (e.g., if the storage slot contains an array or a map).
-- Max code size per account: **no limit** (but we plan to enforce code size limit in the future,
+- Max code size per account: **no limit** (but we plan to enforce a code size limit in the future,
at least for public accounts).
## Notes
- Min assets per note: **0**.
- Max assets per note: **255**.
-- Max inputs per note: **128**. The value can be represented using as a single byte while being
+- Max inputs per note: **128**. The value can be represented as a single byte while being
evenly divisible by 8.
-- Max code size per note: **no limit** (but we plan to enforce code size limit in the future,
+- Max code size per note: **no limit** (but we plan to enforce a code size limit in the future,
at least for public notes).
## Transactions
- Max input notes per transaction: **1024**.
- Max output notes per transaction: **1024**.
-- Max code size of tx script: **no limit** (but we plan to enforce code size limit in the future).
+- Max code size of tx script: **no limit** (but we plan to enforce a code size limit in the future).
- Max number of VM cycles: **$2^{30}$**.
## Batches
diff --git a/docs/architecture/notes.md b/docs/architecture/notes.md
index ac5bbe805..712dd5ae3 100644
--- a/docs/architecture/notes.md
+++ b/docs/architecture/notes.md
@@ -1,7 +1,3 @@
----
-comments: true
----
-
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.
@@ -10,16 +6,16 @@ The concept of notes is a key divergence from Ethereum’s account-based model.
## Note design
-
-![Architecture core concepts](../img/architecture/note/note.png){ width="45%" }
-
+
+
+
-!!! tip "Key to diagram"
- * Assets: An [asset](assets.md) container for a note. It can contain up to `256` assets stored in an array which can be reduced to a single hash.
- * Script: To be executed in the [transaction](https://0xpolygonmiden.github.io/miden-base/architecture/transactions.html) in which the note is consumed. The script defines the conditions for the consumption. If the script fails, the note cannot be consumed.
- * Inputs: Used to execute the note script. They can be accessed by the note script via [transaction kernel procedures](./transactions/kernel.md). A note can be associated with up to `128` input values. Each value is represented by a single field element. Thus, note input values can contain up to `~1` KB of data.
- * Serial number: A note's unique identifier to break link-ability between note hash and [nullifier](#note-nullifier-to-ensure-private-consumption). Should be a random `word` chosen by the user - if revealed, the nullifier might be computed easily.
- * In addition, a note has metadata including the sender and the note tag. Those values are always public regardless of the [note storage mode](#note-storage-mode).
+> **Tip: Key to diagram**
+> - **Assets**: An [asset](assets.md) container for a note. It can contain up to `256` assets stored in an array which can be reduced to a single hash.
+> - **Script**: To be executed in the [transaction](https://0xpolygonmiden.github.io/miden-base/architecture/transactions.html) in which the note is consumed. The script defines the conditions for the consumption. If the script fails, the note cannot be consumed.
+> - **Inputs**: Used to execute the note script. They can be accessed by the note script via [transaction kernel procedures](./transactions/kernel.md). A note can be associated with up to `128` input values. Each value is represented by a single field element. Thus, note input values can contain up to `~1` KB of data.
+> - **Serial number**: A note's unique identifier to break link-ability between note hash and [nullifier](#note-nullifier-to-ensure-private-consumption). Should be a random `word` chosen by the user - if revealed, the nullifier might be computed easily.
+> - In addition, a note has metadata including the sender and the note tag. Those values are always public regardless of the [note storage mode](#note-storage-mode).
## Note lifecycle
@@ -31,9 +27,7 @@ Notes can be produced and consumed locally by users in local transactions or by
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".
-
![Architecture core concepts](../img/architecture/note/note-life-cycle.png)
-
### Note creation
@@ -49,138 +43,140 @@ Note scripts are created together with their inputs, i.e., the creator of the no
There are [standard note scripts](https://github.com/0xPolygonMiden/miden-base/tree/main/miden-lib/asm/note_scripts) (P2ID, P2IDR, SWAP) that users can create and add to their notes using the Miden client or by calling internal [Rust code](https://github.com/0xPolygonMiden/miden-base/blob/fa63b26d845f910d12bd5744f34a6e55c08d5cde/miden-lib/src/notes/mod.rs#L15-L66).
-* 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.
-
-??? 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
-
- The P2ID script uses procedures from the account, note and wallet API.
-
- ```arduino
- use.miden::account
- use.miden::note
- use.miden::contracts::wallets::basic->wallet
- ```
-
- As discussed in detail in [transaction kernel procedures](transactions/procedures.md) certain procedures can only be invoked in certain contexts. The note script is being executed in the note context of the [transaction kernel](transactions/kernel.md).
-
- #### Main script
-
- The main part of the P2ID script checks if the executing account is the same as the account defined in the `NoteInputs`. The creator of the note defines the note script and the note inputs separately to ensure usage of the same standardized P2ID script regardless of the target account ID. That way, it is enough to check the script root (see above).
-
- ```arduino
- # Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
- # matches target account ID specified by the note inputs.
- #
- # Requires that the account exposes: miden::contracts::wallets::basic::receive_asset procedure.
- #
- # Inputs: [SCRIPT_ROOT]
- # Outputs: []
- #
- # Note inputs are assumed to be as follows:
- # - target_account_id is the ID of the account for which the note is intended.
- #
- # FAILS if:
- # - Account does not expose miden::contracts::wallets::basic::receive_asset procedure.
- # - Account ID of executing account is not equal to the Account ID specified via note inputs.
- # - The same non-fungible asset already exists in the account.
- # - Adding a fungible asset would result in amount overflow, i.e., the total amount would be
- # greater than 2^63.
- begin
- # drop the transaction script root
- dropw
- # => []
-
- # load the note inputs to memory starting at address 0
- push.0 exec.note::get_inputs
- # => [inputs_ptr]
-
- # read the target account id from the note inputs
- mem_load
- # => [target_account_id]
-
- exec.account::get_id
- # => [account_id, target_account_id, ...]
-
- # ensure account_id = target_account_id, fails otherwise
- assert_eq
- # => [...]
-
- exec.add_note_assets_to_account
- # => [...]
- end
- ```
-
- 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.
- 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.
-
- #### Add assets
-
- This procedure adds the assets held by the note into the account's vault.
-
- ```arduino
- #! Helper procedure to add all assets of a note to an account.
- #!
- #! Inputs: []
- #! Outputs: []
- #!
- proc.add_note_assets_to_account
- push.0 exec.note::get_assets
- # => [num_of_assets, 0 = ptr, ...]
-
- # compute the pointer at which we should stop iterating
- dup.1 add
- # => [end_ptr, ptr, ...]
-
- # pad the stack and move the pointer to the top
- padw movup.5
- # => [ptr, 0, 0, 0, 0, end_ptr, ...]
-
- # compute the loop latch
- dup dup.6 neq
- # => [latch, ptr, 0, 0, 0, 0, end_ptr, ...]
-
- while.true
- # => [ptr, 0, 0, 0, 0, end_ptr, ...]
-
- # save the pointer so that we can use it later
- dup movdn.5
- # => [ptr, 0, 0, 0, 0, ptr, end_ptr, ...]
-
- # load the asset and add it to the account
- mem_loadw call.wallet::receive_asset
- # => [ASSET, ptr, end_ptr, ...]
-
- # increment the pointer and compare it to the end_ptr
- movup.4 add.1 dup dup.6 neq
- # => [latch, ptr+1, ASSET, end_ptr, ...]
- end
-
- # clear the stack
- drop dropw drop
- end
- ```
-
- The procedure starts by calling `exec.note::get_assets`. As with the note's inputs before, this writes the assets of the note into memory starting at the specified address. Assets are stored in consecutive memory slots, so `dup.1 add` provides the last memory slot.
-
- In Miden, [assets](assets.md) are represented by `Words`, so we need to pad the stack with four `0`s to make room for an asset. Now, if there is at least one asset (checked by `dup dup.6 neq`), the loop starts. It first saves the pointer for later use (`dup movdn.5`), then loads the first asset `mem_loadw` on top of the stack.
-
- Now, the procedure calls the a function of the account interface `call.wallet::receive_asset` to put the asset into the account's vault. Due to different [contexts](https://0xpolygonmiden.github.io/miden-base/transactions/transaction-procedures.html#transaction-contexts), a note script cannot directly call an account function to add the asset. The account must expose this function in its [interface](https://0xpolygonmiden.github.io/miden-base/architecture/accounts.html#example-account-code).
-
- Lastly, the pointer gets incremented, and if there is a second asset, the loop continues (`movup.4 add.1 dup dup.6 neq`). Finally, when all assets were put into the account's vault, the stack is cleared (`drop dropw drop`).
+- 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.
+
+> **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
+>
+> The P2ID script uses procedures from the account, note and wallet API.
+>
+> ```arduino
+> use.miden::account
+> use.miden::note
+> use.miden::contracts::wallets::basic->wallet
+> ```
+>
+> As discussed in detail in [transaction kernel procedures](transactions/procedures.md) certain procedures can only be invoked in certain contexts. The note script is being executed in the note context of the [transaction kernel](transactions/kernel.md).
+>
+> #### Main script
+>
+> The main part of the P2ID script checks if the executing account is the same as the account defined in the `NoteInputs`. The creator of the note defines the note script and the note inputs separately to ensure usage of the same standardized P2ID script regardless of the target account ID. That way, it is enough to check the script root (see above).
+>
+> ```arduino
+> # Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
+> # matches target account ID specified by the note inputs.
+> #
+> # Requires that the account exposes: miden::contracts::wallets::basic::receive_asset procedure.
+> #
+> # Inputs: [SCRIPT_ROOT]
+> # Outputs: []
+> #
+> # Note inputs are assumed to be as follows:
+> # - target_account_id is the ID of the account for which the note is intended.
+> #
+> # FAILS if:
+> # - Account does not expose miden::contracts::wallets::basic::receive_asset procedure.
+> # - Account ID of executing account is not equal to the Account ID specified via note inputs.
+> # - The same non-fungible asset already exists in the account.
+> # - Adding a fungible asset would result in amount overflow, i.e., the total amount would be
+> # greater than 2^63.
+> begin
+> # drop the transaction script root
+> dropw
+> # => []
+>
+> # load the note inputs to memory starting at address 0
+> push.0 exec.note::get_inputs
+> # => [inputs_ptr]
+>
+> # read the target account id from the note inputs
+> mem_load
+> # => [target_account_id]
+>
+> exec.account::get_id
+> # => [account_id, target_account_id, ...]
+>
+> # ensure account_id = target_account_id, fails otherwise
+> assert_eq
+> # => [...]
+>
+> exec.add_note_assets_to_account
+> # => [...]
+> end
+> ```
+>
+> 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.
+> 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.
+>
+> #### Add assets
+>
+> This procedure adds the assets held by the note into the account's vault.
+>
+> ```arduino
+> #! Helper procedure to add all assets of a note to an account.
+> #!
+> #! Inputs: []
+> #! Outputs: []
+> #!
+> proc.add_note_assets_to_account
+> push.0 exec.note::get_assets
+> # => [num_of_assets, 0 = ptr, ...]
+>
+> # compute the pointer at which we should stop iterating
+> dup.1 add
+> # => [
+
+end_ptr, ptr, ...]
+>
+> # pad the stack and move the pointer to the top
+> padw movup.5
+> # => [ptr, 0, 0, 0, 0, end_ptr, ...]
+>
+> # compute the loop latch
+> dup dup.6 neq
+> # => [latch, ptr, 0, 0, 0, 0, end_ptr, ...]
+>
+> while.true
+> # => [ptr, 0, 0, 0, 0, end_ptr, ...]
+>
+> # save the pointer so that we can use it later
+> dup movdn.5
+> # => [ptr, 0, 0, 0, 0, ptr, end_ptr, ...]
+>
+> # load the asset and add it to the account
+> mem_loadw call.wallet::receive_asset
+> # => [ASSET, ptr, end_ptr, ...]
+>
+> # increment the pointer and compare it to the end_ptr
+> movup.4 add.1 dup dup.6 neq
+> # => [latch, ptr+1, ASSET, end_ptr, ...]
+> end
+>
+> # clear the stack
+> drop dropw drop
+> end
+> ```
+>
+> The procedure starts by calling `exec.note::get_assets`. As with the note's inputs before, this writes the assets of the note into memory starting at the specified address. Assets are stored in consecutive memory slots, so `dup.1 add` provides the last memory slot.
+>
+> In Miden, [assets](assets.md) are represented by `Words`, so we need to pad the stack with four `0`s to make room for an asset. Now, if there is at least one asset (checked by `dup dup.6 neq`), the loop starts. It first saves the pointer for later use (`dup movdn.5`), then loads the first asset `mem_loadw` on top of the stack.
+>
+> Now, the procedure calls the a function of the account interface `call.wallet::receive_asset` to put the asset into the account's vault. Due to different [contexts](https://0xpolygonmiden.github.io/miden-base/transactions/transaction-procedures.html#transaction-contexts), a note script cannot directly call an account function to add the asset. The account must expose this function in its [interface](https://0xpolygonmiden.github.io/miden-base/architecture/accounts.html#example-account-code).
+>
+> Lastly, the pointer gets incremented, and if there is a second asset, the loop continues (`movup.4 add.1 dup dup.6 neq`). Finally, when all assets were put into the account's vault, the stack is cleared (`drop dropw drop`).
### Note storage mode
@@ -192,8 +188,8 @@ Every note has a unique note hash. It is defined as follows:
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._
+> **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 tags)
@@ -215,25 +211,25 @@ The two most signification bits of the note tag have the following interpretatio
The following 30 bits can represent anything. In the above example note tag, it represents an account Id of a public account. As designed the first bit of a public account is always `0` which overlaps with the second most significant bit of the note tag.
```
-0b00000100_11111010_01010110_11100010
+0b00000100_11111010_01010160_11100020
```
This example note tag indicates that the network operator (Miden node) executes the note against a specific account - `0x09f4adc47857e2f6`. Only the 30 most significant bits of the account id are represented in the note tag, since account Ids are 64-bit values but note tags only have 32-bits. Knowing a 30-bit prefix already narrows the set of potential target accounts down enough.
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 "Example note tag for P2ID"
- P2ID scripts can only be consumed by the specified account ID (target ID). In the standard schema, the target ID is encoded into the note tag.
-
- For network execution of a P2ID note, the note tag is encoded as follows: 0b00000100_11111010_01010110_11100010. This encoding allows the Miden operator to quickly identify the account against which the transaction must be executed.
-
- For local execution of a P2ID note, the recipient needs to be able to discover the note. The recipient can query the Miden node for a specific tag to see if there are new P2ID notes to be consumed. In this case, the two most significant bits are set to 0b11, allowing any note type (private or public) to be used. The next 14 bits represent the 14 most significant bits of the account ID, and the remaining 16 bits are set to 0.
-
- Example for local execution:
- ```
- 0b11000100_11111010_00000000_00000000
- ```
- This "fuzzy matching" approach balances privacy and efficiency. A note with this tag could be intended for any account sharing the same 16-bit prefix.
+> **Example note tag for P2ID**
+> P2ID scripts can only be consumed by the specified account ID (target ID). In the standard schema, the target ID is encoded into the note tag.
+>
+> For network execution of a P2ID note, the note tag is encoded as follows: 0b00000100_11111010_01010160_11100020. This encoding allows the Miden operator to quickly identify the account against which the transaction must be executed.
+>
+> For local execution of a P2ID note, the recipient needs to be able to discover the note. The recipient can query the Miden node for a specific tag to see if there are new P2ID notes to be consumed. In this case, the two most significant bits are set to 0b11, allowing any note type (private or public) to be used. The next 14 bits represent the 14 most significant bits of the account ID, and the remaining 16 bits are set to 0.
+>
+> Example for local execution:
+> ```
+> 0b11000100_11111010_00000000_00000000
+> ```
+> This "fuzzy matching" approach balances privacy and efficiency. A note with this tag could be intended for any account sharing the same 16-bit prefix.
### Note consumption
@@ -251,7 +247,9 @@ hash(hash(hash(serial_num, [0; 4]), script_hash), input_hash)
This concept restricts note consumption to those users who know the pre-image data of `RECIPIENT` - which might be a bigger set than a single account.
-During the [transaction prologue](transactions/kernel.md) the users needs to provide all the data to compute the note hash. That means, one can create notes that can only be consumed if the `serial_num` and other data is known. This information can be passed off-chain from the sender to the consumer. This is only useful with private notes. For public notes, all note data is known, and anyone can compute the `RECIPIENT`.
+During the [transaction prologue](transactions/kernel.md) the users needs to provide all the data to compute the note hash. That means, one can create notes that can only be consumed if the `serial_num` and other data is known. This information can be passed off-chain from the sender to the consumer. This is only useful with private notes. For public notes,
+
+ all note data is known, and anyone can compute the `RECIPIENT`.
You can see in the standard [SWAP note script](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/note_scripts/SWAP.masm) how `RECIPIENT` is used. Here, using a single hash, is sufficient to ensure that the swapped asset and its note can only be consumed by the defined target.
@@ -271,8 +269,4 @@ This achieves the following properties:
That means if a note is private and the operator stores only the note's hash, only those with the note details know if this note has been consumed already. Zcash first [introduced](https://zcash.github.io/orchard/design/nullifiers.html#nullifiers) this approach.
-
![Architecture core concepts](../img/architecture/note/nullifier.png)
-
-
-
\ No newline at end of file
diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md
index b3ad04e78..62a6f2fe5 100644
--- a/docs/architecture/overview.md
+++ b/docs/architecture/overview.md
@@ -1,7 +1,3 @@
----
-comments: true
----
-
# Miden architecture overview
Polygon Miden’s architecture departs considerably from typical blockchain designs to support privacy and parallel transaction execution.
@@ -68,4 +64,4 @@ Miden's state model captures the individual states of all accounts and notes, an
##### Operators capture and progress state
-![Architecture state process](../img/architecture/miden-architecture-state-progress.gif)
\ No newline at end of file
+![Architecture state process](../img/architecture/miden-architecture-state-progress.gif)
diff --git a/docs/architecture/state.md b/docs/architecture/state.md
index 093149a87..036b54da1 100644
--- a/docs/architecture/state.md
+++ b/docs/architecture/state.md
@@ -1,10 +1,6 @@
----
-comments: true
----
+Miden rollup state describes the current condition of all accounts and notes; i.e. what is currently the case.
-Miden rollup state describes the current condition of all accounts and notes; i.e. what is currently the case.
-
-As the state model uses concurrent off-chain state, Polygon Miden aims for private, and parallel transaction execution and state bloat minimization.
+As the state model uses concurrent off-chain state, Polygon Miden aims for private, and parallel transaction execution and state bloat minimization.
Miden's goals include:
@@ -13,7 +9,7 @@ Miden's goals include:
* Parallel transactions executed concurrently by distinct actors.
* Concurrent state model that allows block production without knowing the full state.
-Privacy is enforced by a UTXO-like state model consisting of notes and nullifiers combined with off-chain execution using zero-knowledge proofs.
+Privacy is enforced by a UTXO-like state model consisting of notes and nullifiers combined with off-chain execution using zero-knowledge proofs.
State bloat describes the ever growing state stored in blockchain nodes. Polygon Miden addresses this challenge via its state model that enables concurrent off-chain execution and off-chain storage. Simply put, users can store their own data locally which reduces the burden on the network while integrity is ensured using zero-knowledge.
@@ -25,9 +21,7 @@ Miden nodes maintain three databases to describe state:
2. A database of notes.
3. A database of nullifiers for already consumed notes.
-
-![Architecture core concepts](../img/architecture/state/state.png){ width="80%" }
-
+![Architecture core concepts](../img/architecture/state/state.png)
These databases are represented by authenticated data structures that enable easy proof of items added to or removed from a database. This ensures that the commitment to the database remains very small.
@@ -37,9 +31,7 @@ Polygon Miden has two databases to capture the note states. The note database is
The latest account states - and data for on-chain accounts - are recorded in a sparse Merkle tree which maps account IDs to account hashes, and account data if needed.
-
-![Architecture core concepts](../img/architecture/state/account-db.png){ width="80%" }
-
+![Architecture core concepts](../img/architecture/state/account-db.png)
As described in the [accounts section](accounts.md), there are two types of accounts:
@@ -48,18 +40,16 @@ As described in the [accounts section](accounts.md), there are two types of acco
Private accounts significantly reduce the storage overhead for nodes. A private account contributes only $40$ bytes to the global state ($8$ bytes account ID + $32$ bytes account hash). Or, said another way, 1 billion private accounts takes up only $40$ GB of state.
-!!! warning
- Losing the state of a private account means loss of funds in a similar manner as a loss of a private key - as the user won't be able to execute transactions. This problem can be mitigated by storing encrypted account state in the cloud or backing it up somewhere else. Unlike storing private keys in the cloud, this does not compromise privacy or account security.
-
- In the future we hope to enable encrypted accounts where the account data is stored on-chain but in an encrypted format. This is especially interesting for shared accounts like advanced multi-sig wallets.
+> **Warning**
+> Losing the state of a private account means loss of funds in a similar manner as a loss of a private key - as the user won't be able to execute transactions. This problem can be mitigated by storing encrypted account state in the cloud or backing it up somewhere else. Unlike storing private keys in the cloud, this does not compromise privacy or account security.
+>
+> In the future we hope to enable encrypted accounts where the account data is stored on-chain but in an encrypted format. This is especially interesting for shared accounts like advanced multi-sig wallets.
### Note database
Notes are recorded in an append-only accumulator, a [Merkle Mountain Range](https://github.com/opentimestamps/opentimestamps-server/blob/master/doc/merkle-mountain-range.md). Each leaf is a block header which contains the commitment to all notes created in that block. The commitment is a Sparse Merkle Tree of all the notes in a block. The size of the Merkle Mountain Range grows logarithmically with the number of items in it.
-
-![Architecture core concepts](../img/architecture/state/note-db.png){ width="80%" }
-
+![Architecture core concepts](../img/architecture/state/note-db.png)
As described in [the notes section](notes.md), there are two types of notes:
@@ -81,16 +71,14 @@ However, the size of the note database does not grow indefinitely. Theoretically
Nullifiers are stored in a sparse Merkle tree, which maps [note nullifiers](notes.md#note-nullifier-to-ensure-private-consumption) to block numbers at which the nullifiers are inserted into the chain (or to `0` for nullifiers which haven't been recorded yet). Nullifiers provide information on whether a specific note has been consumed. The database allows proving that a given nullifier is not in the database.
-
-![Architecture core concepts](../img/architecture/state/nullifier-db.png){ width="80%" }
-
+![Architecture core concepts](../img/architecture/state/nullifier-db.png)
To prove that a note has not been consumed previously, the operator needs to provide a Merkle path to its node, and then show that the value in that node is `0`. In our case nullifiers are $32$ bytes each, and thus, the height of the Sparse Merkle Tree needs to be $256$.
To add new nullifiers to the database, operators need to maintain the entire nullifier set. Otherwise, they would not be able to compute the new root of the tree.
-!!! note
- Nullifiers as constructed in Miden break linkability of privately stored notes and the information about the note's consumption. To know the [note's nullifier](notes.md#note-nullifier-to-ensure-private-consumption) one must know the note's data.
+> **Note**
+> Nullifiers as constructed in Miden break linkability of privately stored notes and the information about the note's consumption. To know the [note's nullifier](notes.md#note-nullifier-to-ensure-private-consumption) one must know the note's data.
In the future, when the network experiences a large number of transactions per second (TPS), there will be one tree per epoch (~3 months), and Miden nodes always store trees for at least two epochs. However, the roots of the old trees are still stored. If a user wants to consume a note that is more than $6$ months old, there must be a merkle path provided to the Miden Node for verification.
diff --git a/docs/architecture/transactions/contexts.md b/docs/architecture/transactions/contexts.md
index e398d6515..963234006 100644
--- a/docs/architecture/transactions/contexts.md
+++ b/docs/architecture/transactions/contexts.md
@@ -1,26 +1,20 @@
----
-comments: true
----
-
## Context overview
-Miden assembly program execution, the code the transaction kernel runs, spans multiple isolated contexts. An execution context defines its own memory space which is inaccessible from other execution contexts. Note scripts cannot directly write to account data which should only be possible if the account exposes relevant functions.
+Miden assembly program execution, the code the transaction kernel runs, spans multiple isolated contexts. An execution context defines its own memory space which is inaccessible from other execution contexts. Note scripts cannot directly write to account data, which should only be possible if the account exposes relevant functions.
## Specific contexts
The kernel program always starts executing from a root context. Thus, the prologue sets the memory for the root context. To move execution into a different context, the kernel invokes a procedure using the `call` or `dyncall` instruction. In fact, any time the kernel invokes a procedure using the `call` instruction, it executes in a new context.
-While executing in a note, account, or tx script context, the kernel executes some procedures in the kernel context, which is where all necessary information was stored during the prologue. The kernel switches context via the `syscall` instruction. The set of procedures invoked via the `syscall` instruction is limited by the [transaction kernel API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/kernels/transaction/api.masm). When the procedure called via `syscall` returns, execution moves back to the note, account, or tx script where it was invoked.
+While executing in a note, account, or transaction (tx) script context, the kernel executes some procedures in the kernel context, where all necessary information is stored during the prologue. The kernel switches context via the `syscall` instruction. The set of procedures invoked via the `syscall` instruction is limited by the [transaction kernel API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/kernels/transaction/api.masm). When the procedure called via `syscall` returns, execution moves back to the note, account, or tx script where it was invoked.
## Context switches
-
![Transaction contexts](../../img/architecture/transaction/transaction-contexts.png)
-
The above diagram shows different context switches in a simple transaction. In this example, an account consumes a [P2ID](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/note_scripts/P2ID.masm) note and receives the asset into its vault. As with any MASM program, the transaction kernel program starts in the root context. It executes the prologue and stores all necessary information into the root memory.
-The next step, note processing, starts with a `dyncall` which invokes the note script. This command moves execution into a different context **(1)**. In this new context, the note has no access to the kernel memory. After a successful ID check, which changes back to the kernel context twice to get the note inputs and the account id, the script executes the `add_note_assets_to_account` procedure.
+The next step, note processing, starts with a `dyncall` which invokes the note script. This command moves execution into a different context **(1)**. In this new context, the note has no access to the kernel memory. After a successful ID check, which changes back to the kernel context twice to get the note inputs and the account ID, the script executes the `add_note_assets_to_account` procedure.
```arduino
# Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
@@ -64,7 +58,7 @@ export.receive_asset
end
```
-The [account API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/miden/account.masm#L162) exposes procedures to manage accounts. This particular procedure that was called by the wallet invokes a `syscall` to return back to the root context **(3)**, where the account vault is stored in memory (see prologue). Procedures defined in the [Kernel API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/kernels/transaction/api.masm) should be invoked with `syscall` using the corresponding [procedure offset](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/miden/kernel_proc_offsets.masm) and the `exec_kernel_proc` kernel procedure.
+The [account API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/miden/account.masm#L162) exposes procedures to manage accounts. This particular procedure, called by the wallet, invokes a `syscall` to return back to the root context **(3)**, where the account vault is stored in memory (see prologue). Procedures defined in the [Kernel API](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/kernels/transaction/api.masm) should be invoked with `syscall` using the corresponding [procedure offset](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/miden/kernel_proc_offsets.masm) and the `exec_kernel_proc` kernel procedure.
```arduino
#! Add the specified asset to the vault.
@@ -76,5 +70,3 @@ end
```
Now, the asset can be safely added to the vault within the kernel context, and the note can be successfully processed.
-
-
diff --git a/docs/architecture/transactions/execution.md b/docs/architecture/transactions/execution.md
index e4149cc9a..d8f746fc5 100644
--- a/docs/architecture/transactions/execution.md
+++ b/docs/architecture/transactions/execution.md
@@ -1,7 +1,3 @@
----
-comments: true
----
-
The Miden transaction executor is the component that executes transactions.
Transaction execution consists of the following steps and results in an `ExecutedTransaction` object:
@@ -11,11 +7,9 @@ Transaction execution consists of the following steps and results in an `Execute
3. Execute the transaction program and create an `ExecutedTransaction` object.
4. Prove the `ExecutedTransaction` using the transaction prover.
-
![Transaction execution process](../../img/architecture/transaction/transaction-execution-process.png)
-
-One of the main reasons for separating out the execution and proving steps is to allow _stateless provers_; i.e. the executed transaction has all the data it needs to re-execute and prove a transaction without database access. This supports easier proof-generation distribution.
+One of the main reasons for separating out the execution and proving steps is to allow _stateless provers_; i.e., the executed transaction has all the data it needs to re-execute and prove a transaction without database access. This supports easier proof-generation distribution.
## Data store and transaction inputs
@@ -24,11 +18,11 @@ The data store defines the interface that transaction objects use to fetch the d
- `Account` data which includes the [AccountID](../accounts.md#account-id) and the [AccountCode](../accounts.md#code) that is executed during the transaction.
- A `BlockHeader` which contains metadata about the block, commitments to the current state of the chain, and the hash of the proof that attests to the integrity of the chain.
- A `ChainMmr` which authenticates input notes during transaction execution. Authentication is achieved by providing an inclusion proof for the transaction's input notes against the `ChainMmr`-root associated with the latest block known at the time of transaction execution.
-- `InputNotes` consumed by the transaction that include the corresponding note data, e.g. the [note script](../notes.md#the-note-script) and serial number.
+- `InputNotes` consumed by the transaction that include the corresponding note data, e.g., the [note script](../notes.md#the-note-script) and serial number.
-!!! note
- - `InputNotes` must be already recorded on-chain in order for the transaction to succeed.
- - There is no nullifier-check during a transaction. Nullifiers are checked by the Miden operator during transaction verification. So at the transaction level, there is "double spending".
+> **Note**
+> - `InputNotes` must be already recorded on-chain in order for the transaction to succeed.
+> - There is no nullifier-check during a transaction. Nullifiers are checked by the Miden operator during transaction verification. So at the transaction level, there is "double spending."
## Transaction compiler
@@ -42,12 +36,10 @@ After compilation, assuming correctly-populated inputs, including the advice pro
## Executed transactions and the transaction outputs
-The `ExecutedTransaction` object represents the result of a transaction not its proof. From this object, the account and storage delta can be extracted. Furthermore, the `ExecutedTransaction` is an input to the transaction prover.
+The `ExecutedTransaction` object represents the result of a transaction, not its proof. From this object, the account and storage delta can be extracted. Furthermore, the `ExecutedTransaction` is an input to the transaction prover.
A successfully executed transaction results in a new account state which is a vector of all created notes (`OutputNotes`) and a vector of all the consumed notes (`InputNotes`) together with their nullifiers.
## Transaction prover
The transaction prover proves the inputted `ExecutedTransaction` and returns a `ProvenTransaction` object. The Miden node verifies the `ProvenTransaction` object using the transaction verifier and, if valid, updates the [state](../state.md) databases.
-
-
diff --git a/docs/architecture/transactions/kernel.md b/docs/architecture/transactions/kernel.md
index 22219407c..c566af862 100644
--- a/docs/architecture/transactions/kernel.md
+++ b/docs/architecture/transactions/kernel.md
@@ -1,15 +1,13 @@
----
-comments: true
----
+# Transaction Kernel Program
-The transaction kernel program, written in [MASM](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html), is responsible for executing a Miden rollup transaction within the Miden VM. It is defined as MASM [kernel](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/execution_contexts.html#kernels).
+The transaction kernel program, written in [MASM](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html), is responsible for executing a Miden rollup transaction within the Miden VM. It is defined as a MASM [kernel](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/execution_contexts.html#kernels).
-The kernel provides context-sensitive security which prevents unwanted read and write access. It defines a set of procedures which can be invoked from other [contexts](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/execution_contexts.html#execution-contexts); e.g. notes executed in the root context.
+The kernel provides context-sensitive security, preventing unwanted read and write access. It defines a set of procedures which can be invoked from other [contexts](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/execution_contexts.html#execution-contexts); e.g., notes executed in the root context.
-In general, the kernel's procedures must reflect everything users might want to do while executing transactions; from transferring assets to complex smart contract interactions with custom code.
+In general, the kernel's procedures must reflect everything users might want to do while executing transactions—from transferring assets to complex smart contract interactions with custom code.
-!!! info
- - Learn more about Miden transaction [procedures](procedures.md) and [contexts](contexts.md).
+> **Info**
+> - Learn more about Miden transaction [procedures](procedures.md) and [contexts](contexts.md).
The kernel has a well-defined structure which does the following:
@@ -18,142 +16,104 @@ The kernel has a well-defined structure which does the following:
3. Transaction script processing executes the optional transaction script.
4. The [epilogue](#epilogue) finalizes the transaction by computing the output notes commitment, the final account hash, asserting asset invariant conditions, and asserting the nonce rules are upheld.
-
![Transaction program](../../img/architecture/transaction/transaction-program.png)
-
## Input
-The transaction kernel program receives two types of inputs, public inputs via the `operand_stack` and private inputs via the `advice_provider`.
+The transaction kernel program receives two types of inputs: public inputs via the `operand_stack` and private inputs via the `advice_provider`.
-The operand stack holds the global inputs which serve as a commitment to the data being provided via the advice provider.
-
-The advice provider holds data of the last known block, account and input note data. The details are laid out in the next paragraph.
+- **Operand stack**: Holds the global inputs which serve as a commitment to the data being provided via the advice provider.
+- **Advice provider**: Holds data of the last known block, account, and input note data.
## Prologue
-The transaction prologue executes at the beginning of a transaction.
-
-It performs the following tasks:
+The transaction prologue executes at the beginning of a transaction. It performs the following tasks:
1. _Unhashes_ the inputs and lays them out in the root context memory.
-2. Builds a single vault (tx vault) containing assets of all inputs (input notes and initial account state).
+2. Builds a single vault (transaction vault) containing assets of all inputs (input notes and initial account state).
3. Verifies that all input notes are present in the note DB.
-In other words, the prologue stores all provided information from the inputs and the advice provider into the appropriate memory slots. It then reads the data for the account and notes from the advice provider, writes it to memory, hashes it, and verifies that the resulting hash matches the commitments provided via the stack. Finally, it creates a single vault for the assets that are involved.
-
-The diagram below shows the memory layout. The kernel context has access to all memory slots.
+The memory layout is illustrated below. The kernel context has access to all memory slots.
-
![Memory layout kernel](../../img/architecture/transaction/memory-layout-kernel.png)
-
### Bookkeeping section
-The bookkeeping section keeps track of variables which are used internally by the transaction kernel.
+Tracks variables used internally by the transaction kernel.
### Global inputs
-These are stored in the pre-defined memory slots.
-
-Global inputs come from the `operand_stack` and go to the VM at transaction execution. They include the block hash, the account ID, the initial account hash, and the nullifier commitment. This is a sequential hash of all `(nullifier, ZERO)` pairs for the notes consumed in the transaction.
+Stored in pre-defined memory slots. Global inputs include the block hash, account ID, initial account hash, and nullifier commitment.
### Block data
-The block data processing involves reading the block data from the advice provider and storing it at the appropriate memory addresses. Block data comes from the latest known block and consists of note, state and tx hash, the block's previous hash and proof hash, as well as the block number. As the data is read from the advice provider, the block hash is computed. It is asserted that the computed block hash matches the block hash stored in the global inputs.
+Block data, read from the advice provider, is stored in memory. The block hash is computed and verified against the global inputs.
### Chain data
-Chain data is processed in a similar way to block data. In this case the chain root is recomputed and compared against the chain root stored in the block data section.
+Chain root is recomputed and verified against the chain root in the block data section.
### Account data
-Account data processing involves reading the data from the advice provider and storing it at the appropriate memory addresses. The account data consists of account vault roots, storage, and code.
-
-As the account data is read from the advice provider, the account hash is computed. If the account is new then the global initial account hash is updated and the new account is validated. If the account already exists then the computed account hash is asserted against the account hash provided via global inputs. It is also asserted that the account id matches the account id provided via the global inputs (`operand_stack`).
+Reads data from the advice provider, stores it in memory, and computes the account hash. The hash is validated against global inputs. For new accounts, initial account hash and validation steps are applied.
### Input note data
-Input note processing involves the kernel reading the data from each note and storing it at the appropriate memory addresses. All the data (note, account, and blockchain data) comes from the advice provider and global inputs.
-
-Next to the total number of input notes, input note data consists of a serial number, the roots of the script, the inputs and asset vault, its metadata, and all its assets.
+Processes input notes by reading data from advice providers and storing it in memory. It computes the note's hash and nullifier, forming a transaction nullifier commitment.
-As each note is consumed, its hash and nullifier are computed.
+> **Info**
+> - Note data is required for computing the nullifier (e.g., the [note script](../notes.md#main-script) and serial number).
+> - Note recipients define the set of users who can consume specific notes.
-The transaction nullifier commitment is computed via a sequential hash of `(nullifier, ZERO)` pairs for all input notes. This step involves authentication such that the input note data provided via the advice provider is consistent with the chain history.
+## Note Processing
-!!! info
- - Note data is required for computing the nullifier, e.g. the [note script](../notes.md#main-script) and the serial number.
- - The system needs to know the note data to execute the prologue of a transaction. This is how the [note recipient](../notes.md#note-recipient-to-restrict-note-consumption) defines the set of users who can consume a specific note.
- - The executing account provides the pre-image data to the recipient at the time of execution.
-
-If a transaction script is provided, its root is stored at a pre-defined memory address.
-
-## Note processing
-
-Input notes are consumed in a loop.
-
-For every note, the [MAST root](https://0xpolygonmiden.github.io/miden-vm/design/programs.html) of the note script is loaded onto the stack. Then, by calling a [`dyncall`](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/code_organization.html?highlight=dyncall#dynamic-procedure-invocation) the note script is executed in a new context which prevents unwanted memory access.
+Notes are consumed in a loop, invoking their scripts in isolated contexts using `dyncall`.
```arduino
- # loop while we have notes to consume
- while.true
- # execute the note setup script
- exec.note::prepare_note
- # => [note_script_root_ptr, NOTE_ARGS]
-
- # invoke the note script using the dyncall instruction
- dyncall
- # => [OUTPUT_3, OUTPUT_2, OUTPUT_1, OUTPUT_0]
-
- # clean up note script outputs
- dropw dropw dropw dropw
- # => []
-
- # check if we have more notes to consume and should loop again
- exec.note::increment_current_input_note_ptr
- loc_load.0
- neq
- # => [should_loop]
- end
+# loop while we have notes to consume
+while.true
+ exec.note::prepare_note
+ dyncall
+ dropw dropw dropw dropw
+ exec.note::increment_current_input_note_ptr
+ loc_load.0
+ neq
+end
```
-When processing a note, new note creation might be triggered. If so, all necessary information about the new note is stored in the *output note data* in memory.
-
-!!! info
- - The Miden transaction kernel program prevents notes from having direct access to account storage.
- - Notes can only call the account interface to trigger write operations in the account.
+When processing a note, new note creation may be triggered, and information about the new note is stored in the output note data.
-## Transaction script processing
+> **Info**
+> - Notes can only call account interfaces to trigger write operations, preventing direct access to account storage.
-If a transaction script is provided with the transaction, it is processed after all notes are consumed. By loading the transaction script root onto the stack, the kernel can invoke a `dyncall` and in doing so execute the script. The transaction script is then again executed in its own context.
+## Transaction Script Processing
-The transaction script can be used to authenticate the transaction by increasing the account's nonce and signing the transaction, as in the following example:
+If provided, the transaction script is executed after all notes are consumed. The script may authenticate the transaction by increasing the account nonce and signing the transaction.
```arduino
- use.miden::contracts::auth::basic->auth_tx
+use.miden::contracts::auth::basic->auth_tx
- begin
- call.auth_tx::auth_tx_rpo_falcon512
- end
+begin
+ call.auth_tx::auth_tx_rpo_falcon512
+end
```
-!!! note
- - The executing account must expose the `auth_tx_rpo_falcon512` function in order for the transaction script to call it.
+> **Note**
+> - The account must expose the `auth_tx_rpo_falcon512` function for the transaction script to call it.
## Epilogue
-The epilogue finalizes the transaction. It does the following:
+Finalizes the transaction:
1. Computes the final account hash.
-2. If the account has changed, it asserts that the final account nonce is greater than the initial account nonce.
+2. Asserts that the final account nonce is greater than the initial nonce if the account has changed.
3. Computes the output notes commitment.
-4. Asserts that the input and output vault roots are equal.
-
-There is an exception for special accounts, called faucets, which can mint or burn assets. In these cases, input and output vault roots are not equal.
+4. Asserts that input and output vault roots are equal (except for special accounts like faucets).
## Outputs
-The transaction kernel program outputs the transaction script root, a commitment of all newly created outputs notes, and the account hash in its new state.
+The transaction kernel program outputs:
-
+1. The transaction script root.
+2. A commitment of all newly created output notes.
+3. The account hash in its new state.
diff --git a/docs/architecture/transactions/overview.md b/docs/architecture/transactions/overview.md
index 1069dd34e..c3fc4d103 100644
--- a/docs/architecture/transactions/overview.md
+++ b/docs/architecture/transactions/overview.md
@@ -1,23 +1,19 @@
----
-comments: true
----
-
# Transactions overview
## Architecture overview
The Miden transaction architecture comprises a set of components that interact with each other. This section of the documentation discusses each component.
-The diagram shows the components responsible for Miden transactions and how they fit together.
+The diagram shows the components responsible for Miden transactions and how they fit together.
-
-![Transactions architecture overview](../../img/architecture/transaction/tx-overview.png)
-
+
+
+
-!!! tip "Key to diagram"
- - The [transaction executor](execution.md) prepares, executes, and proves transactions.
- - The executor compiles the [transaction kernel](kernel.md) plus user-defined notes and transaction scripts into a single executable program for the Miden VM.
- - Users write scripts using [kernel procedures](procedures.md) and [contexts](contexts.md).
+> **Tip**
+> - The [transaction executor](execution.md) prepares, executes, and proves transactions.
+> - The executor compiles the [transaction kernel](kernel.md) plus user-defined notes and transaction scripts into a single executable program for the Miden VM.
+> - Users write scripts using [kernel procedures](procedures.md) and [contexts](contexts.md).
## Miden transactions
@@ -27,28 +23,24 @@ A transaction takes a single account and some [notes](../notes.md) as input, and
Miden aims for the following:
-- Parallel transaction execution: Because a transaction is always performed against a single account, Miden obtains asynchronicity.
-- Private transaction execution: Because every transaction emits a state-change with a STARK proof, there is privacy when the transaction executes locally.
+- **Parallel transaction execution**: Because a transaction is always performed against a single account, Miden obtains asynchronicity.
+- **Private transaction execution**: Because every transaction emits a state-change with a STARK proof, there is privacy when the transaction executes locally.
-There are two types of transactions in Miden: local transactions and network transactions.
+There are two types of transactions in Miden: **local transactions** and **network transactions**.
## Transaction design
Transactions describe the state-transition of a single account that takes chain data and `0 to 1024` notes as input and produces a `TransactionWitness` and `0 to 1024` notes as output.
-
![Transaction diagram](../../img/architecture/transaction/transaction-diagram.png){ width="75%" }
-
-At its core, a transaction is an executable program - the transaction kernel program - that processes the provided inputs and creates the requested outputs. Because the program is executed by the Miden VM, a STARK-proof is generated for every transaction.
+At its core, a transaction is an executable program—the transaction kernel program—that processes the provided inputs and creates the requested outputs. Because the program is executed by the Miden VM, a STARK-proof is generated for every transaction.
## Asset transfer using two transactions
Transferring assets between accounts requires two transactions as shown in the diagram below.
-
![Transaction flow](../../img/architecture/transaction/transaction-flow.png)
-
The first transaction invokes some functions on `account_a` (e.g. `create_note` and `move_asset_to_note` functions) which creates a new note and also updates the internal state of `account_a`. The second transaction consumes the note which invokes a function on `account_b` (e.g. a `receive_asset` function) which updates the internal state of `account_b`.
@@ -58,16 +50,14 @@ Both transactions can be executed asynchronously: first `transaction1` is execut
This opens up a few interesting possibilities:
-* Owner of `account_b` may wait until they receive many notes and process them all in a single transaction.
-* A note script may include a clause which allows the source account to consume the note after some time. Thus, if `account_b` does not consume the note after the specified time, the funds can be returned. This mechanism can be used to make sure funds sent to non-existent accounts are not lost (see the [P2IDR note script](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/note_scripts/P2IDR.masm)).
-* Neither sender nor the recipient need to know who the other side is. From the sender's perspective they just need to create `note1` (and for this they need to know the assets to be transferred and the root of the note's script). They don't need any information on who will eventually consume the note. From the recipient's perspective, they just need to consume `note1`. They don't need to know who created it.
-* Both transactions can be executed "locally". For example, we could generate a zk-proof that `transaction1` was executed and submit it to the network. The network can verify the proof without the need for executing the transaction itself. The same can be done for `transaction2`. Moreover, we can mix and match. For example, `transaction1` can be executed locally, but `transaction2` can be executed on the network, or vice-versa.
+- The owner of `account_b` may wait until they receive many notes and process them all in a single transaction.
+- A note script may include a clause which allows the source account to consume the note after some time. Thus, if `account_b` does not consume the note after the specified time, the funds can be returned. This mechanism can be used to make sure funds sent to non-existent accounts are not lost (see the [P2IDR note script](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/note_scripts/P2IDR.masm)).
+- Neither the sender nor the recipient needs to know who the other side is. From the sender's perspective, they just need to create `note1` (and for this they need to know the assets to be transferred and the root of the note's script). They don't need any information on who will eventually consume the note. From the recipient's perspective, they just need to consume `note1`. They don't need to know who created it.
+- Both transactions can be executed "locally". For example, we could generate a zk-proof that `transaction1` was executed and submit it to the network. The network can verify the proof without the need for executing the transaction itself. The same can be done for `transaction2`. Moreover, we can mix and match. For example, `transaction1` can be executed locally, but `transaction2` can be executed on the network, or vice versa.
## Local and network transactions
-
![Local vs network transactions](../../img/architecture/transaction/local-vs-network-transaction.png)
-
### Local transactions
@@ -75,7 +65,7 @@ This is where clients executing the transactions also generate the proofs of the
Local transactions are useful for several reasons:
-1. They are cheaper (i.e. lower fees) as zk-proofs are already generated by the clients.
+1. They are cheaper (i.e., lower fees) as zk-proofs are already generated by the clients.
2. They allow fairly complex computations because the proof size doesn't grow linearly with the complexity of the computation.
3. They enable privacy as neither the account state nor account code are needed to verify the zk-proof.
@@ -87,5 +77,3 @@ Network transactions are useful for two reasons:
1. Clients may not have sufficient resources to generate zk-proofs.
2. Executing many transactions against the same public account by different clients is challenging, as the account state changes after every transaction. Due to this, the Miden node/operator acts as a "synchronizer" to execute transactions sequentially by feeding the output of the previous transaction into the input of the next.
-
-
\ No newline at end of file
diff --git a/docs/architecture/transactions/procedures.md b/docs/architecture/transactions/procedures.md
index 82f86eed9..50095afb2 100644
--- a/docs/architecture/transactions/procedures.md
+++ b/docs/architecture/transactions/procedures.md
@@ -1,15 +1,11 @@
----
-comments: true
----
-
There are user-facing procedures and kernel procedures. Users don't directly invoke kernel procedures, but instead they invoke them indirectly via account code, note, or transaction scripts. In these cases, kernel procedures are invoked by a `syscall` instruction which always executes in the kernel context.
## User-facing procedures (APIs)
These procedures can be used to create smart contract/account code, note scripts, or account scripts. They basically serve as an API for the underlying kernel procedures. If a procedure can be called in the current context, an `exec` is sufficient. Otherwise the context procedures must be invoked by `call`. Users never need to invoke `syscall` procedures themselves.
-!!! tip
- If capitalized, a variable representing a `word`, e.g., `ACCT_HASH` consists of four `felts`. If lowercase, the variable is represented by a single `felt`.
+> **Tip**
+> If capitalized, a variable representing a `word`, e.g., `ACCT_HASH` consists of four `felts`. If lowercase, the variable is represented by a single `felt`.
### Account
diff --git a/docs/img/get-started/account-a.png b/docs/img/get-started/account-a.png
deleted file mode 100644
index 4d01f73a56fc993208ae7c121cf8bc80a9303039..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 51865
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
yu^c#)K+W8nGPkmNbnEqNBYfp|
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