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%" } -
+

+ Account diagram +

-!!! 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%" } -
+

+ Note diagram +

-!!! 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) -
+

+ Transactions architecture overview +

-!!! 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 4d01f73a5..000000000 Binary files a/docs/img/get-started/account-a.png and /dev/null differ diff --git a/docs/img/get-started/account-b.png b/docs/img/get-started/account-b.png deleted file mode 100644 index b85107c31..000000000 Binary files a/docs/img/get-started/account-b.png and /dev/null differ diff --git a/docs/img/get-started/commit-height.png b/docs/img/get-started/commit-height.png deleted file mode 100644 index 026938187..000000000 Binary files a/docs/img/get-started/commit-height.png and /dev/null differ diff --git a/docs/img/get-started/consumed-note.png b/docs/img/get-started/consumed-note.png deleted file mode 100644 index 391ff1140..000000000 Binary files a/docs/img/get-started/consumed-note.png and /dev/null differ diff --git a/docs/img/get-started/miden-account-list.png b/docs/img/get-started/miden-account-list.png deleted file mode 100644 index 309157447..000000000 Binary files a/docs/img/get-started/miden-account-list.png and /dev/null differ diff --git a/docs/img/get-started/note-view.png b/docs/img/get-started/note-view.png deleted file mode 100644 index 1a3d09642..000000000 Binary files a/docs/img/get-started/note-view.png and /dev/null differ diff --git a/docs/img/get-started/processing-note.png b/docs/img/get-started/processing-note.png deleted file mode 100644 index 356215aea..000000000 Binary files a/docs/img/get-started/processing-note.png and /dev/null differ diff --git a/docs/img/get-started/transaction-confirmation.png b/docs/img/get-started/transaction-confirmation.png deleted file mode 100644 index e535a88f6..000000000 Binary files a/docs/img/get-started/transaction-confirmation.png and /dev/null differ diff --git a/docs/img/get-started/two-accounts.png b/docs/img/get-started/two-accounts.png deleted file mode 100644 index 9c989073f..000000000 Binary files a/docs/img/get-started/two-accounts.png and /dev/null differ diff --git a/docs/img/get-started/view-account-vault.png b/docs/img/get-started/view-account-vault.png deleted file mode 100644 index e2eeaa9f6..000000000 Binary files a/docs/img/get-started/view-account-vault.png and /dev/null differ diff --git a/docs/index.md b/docs/index.md index 9ec87c35b..5705bc82c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ A rollup for high-throughput, private applications. -Using Polygon Miden, builders can create novel, high-throughput, private applications for payments, DeFi, digital assets and gaming. Applications and users are secured by Ethereum and AggLayer. +Using Polygon Miden, builders can create novel, high-throughput, private applications for payments, DeFi, digital assets, and gaming. Applications and users are secured by Ethereum and AggLayer. If you want to join the technical discussion, please check out the following: @@ -10,18 +10,18 @@ If you want to join the technical discussion, please check out the following: * [Miden repo](https://github.com/0xPolygonMiden) * [Roadmap](introduction/roadmap.md) -!!! info - - These docs are still work-in-progress. - - Some topics have been discussed in greater depth, while others require additional clarification. +> **Info** +> - These docs are still work-in-progress. +> - Some topics have been discussed in greater depth, while others require additional clarification. ## Status and features -Polygon Miden is currently on release v0.6. This is an early version of the protocol and its components. +Polygon Miden is currently on release v0.7. This is an early version of the protocol and its components. -!!! important - We expect breaking changes on all components. +> **Important** +> We expect breaking changes on all components. -At the time of writing, Polygon Miden doesn't offer all the features you may expect from a zkRollup. During 2024, we expect to gradually implement more features. +At the time of writing, Polygon Miden doesn't offer all the features you may expect from a zkRollup. During 2024, we expect to gradually implement more features. ### Feature highlights @@ -35,19 +35,19 @@ Like private accounts, the Miden operator only tracks a commitment to notes in t #### Public accounts -Polygon Miden supports public smart contracts like Ethereum. The code and state of those accounts is visible to the network and anyone can execute transactions against them. +Polygon Miden supports public smart contracts like Ethereum. The code and state of those accounts are visible to the network and anyone can execute transactions against them. #### Public notes As with public accounts, public notes are also supported. That means, the Miden operator publicly stores note data. Note consumption is not private. -#### Local transaction execution +#### Local transaction execution The Miden client allows for local transaction execution and proving. The Miden operator verifies the proof and, if valid, updates the state DBs with the new data. #### Simple smart contracts -Currently, there are three different smart contracts available. A basic wallet smart contract that sends and receives assets, and fungible and non-fungible faucets to mint and burn assets. +Currently, there are three different smart contracts available. A basic wallet smart contract that sends and receives assets, and fungible and non-fungible faucets to mint and burn assets. All accounts are written in [MASM](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html). @@ -57,7 +57,7 @@ Currently, there are three different note scripts available. Two different versi #### Simple block building -The Miden operator running the Miden node builds the blocks containing transactions. +The Miden operator running the Miden node builds the blocks containing transactions. #### Maintaining state @@ -65,8 +65,8 @@ The Miden node stores all necessary information in its state DBs and provides th ### Planned features -!!! warning - The following features are at a planning stage only. +> **Warning** +> The following features are at a planning stage only. #### Customized smart contracts diff --git a/docs/introduction/get-started/create-account-use-faucet.md b/docs/introduction/get-started/create-account-use-faucet.md deleted file mode 100644 index 26bc3c270..000000000 --- a/docs/introduction/get-started/create-account-use-faucet.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -comments: true ---- - -In this section, we show you how to create a new local Miden account and how to receive funds from the public Miden faucet website. - -## Configure the Miden client - -The Miden client facilitates interaction with the Miden rollup and provides a way to execute and prove transactions. - -!!! tip - Check the [Miden client documentation](https://docs.polygon.technology/miden/miden-client/cli-reference/) for more information. - -1. If you haven't already done so as part of another tutorial, open your terminal and create a new directory to store the Miden client. - - ```sh - mkdir miden-client - cd miden-client - ``` - -2. Install the Miden client. - - ```shell - cargo install miden-cli --features testing,concurrent - ``` - You can now use the `miden --version` command, and you should see `Miden 0.6.0`. - -3. Initialize the client. This creates the `miden-client.toml` file. - -```shell -miden init --rpc 18.203.155.106 -``` -For the --rpc flag, enter the IP that the Miden team supplied. - -## Create a new Miden account - -1. Create a new account of type `mutable` using the following command: - - ```shell - miden new-wallet --mutable - ``` - -2. List all created accounts by running the following command: - - ```shell - miden account -l - ``` - You should see something like this: - - ![Result of listing miden accounts](../../img/get-started/miden-account-list.png) - -Save the account ID for a future step. - -## Request tokens from the public faucet - -1. To request funds from the faucet navigate to the following website: [Miden faucet website](https://testnet.miden.io/). - -2. Copy the **Account ID** printed by the `miden account -l` command in the previous step. Feel free to change the amount of tokens to issue. - -3. Paste this ID into the **Request test tokens** input field on the faucet website and click **Send Private Note**. - -!!! tip - You can also click **Send Public Note**. If you do this, the note's details will be public and you will not need to download and import it, so you can skip to [Sync the client](#sync-the-client). - -4. After a few seconds your browser should download - or prompt you to download - a file called `note.mno` (mno = Miden note). It contains the funds the faucet sent to your address. - -5. Save this file on your computer, you will need it for the next step. - -## Import the note into the Miden client - -1. Import the private note that you have received using the following commands: - - ```shell - miden import /note.mno - ``` - -2. You should see something like this: - - ```sh - Successfully imported note 0x0ff340133840d35e95e0dc2e62c88ed75ab2e383dc6673ce0341bd486fed8cb6 - ``` - -3. Now that the note has been successfully imported, you can view the note's information using the following command: - - ```shell - miden notes - ``` - -4. You should see something like this: - - ![Result of viewing miden notes](../../img/get-started/note-view.png) - -!!! tip "The importance of syncing" - - As you can see, the note is listed as `Expected`. - - This is because you have received a private note but have not yet synced your view of the rollup to check that the note is the result of a valid transaction. - - Hence, before consuming the note we will need to update our view of the rollup by syncing. - - Many users could have received the same private note, but only one user can consume the note in a transaction that gets verified by the Miden operator. - -### Sync the client - -Do this periodically to keep informed about any updates on the node by running the `sync` command: - -```shell -miden sync -``` - -You will see something like this as output: - -```sh -State synced to block 179672 -New public notes: 0 -Tracked notes updated: 1 -Tracked notes consumed: 0 -Tracked accounts updated: 0 -Commited transactions: 0 -``` - -## Consume the note & receive the funds - -1. Now that we have synced the client, the input-note imported from the faucet should have a `Committed` status, confirming it exists at the rollup level: - - ```shell - miden notes - ``` - -2. You should see something like this: - - ![Viewing commit height info](../../img/get-started/commit-height.png) - -3. Find your account and note id by listing both `accounts` and `notes`: - - ```shell - miden account - miden notes - ``` - -4. Consume the note and add the funds from its vault to our account using the following command: - - ```shell - miden consume-notes --account - ``` - -5. You should see a confirmation message like this: - - ![Transaction confirmation message](../../img/get-started/transaction-confirmation.png) - -6. After confirming you can view the new note status by running the following command: - - ```shell - miden notes - ``` - -7. You should see something like this: - - ![Viewing process info](../../img/get-started/processing-note.png) - -8. The note is `Processing`. This means that the proof of the transaction was sent, but there is no network confirmation yet. You can update your view of the rollup by syncing again: - - ```shell - miden sync - ``` - -9. After syncing, you should have received confirmation of the consumed note. You should see the note as `Consumed` after listing the notes: - - ```shell - miden notes - ``` - - ![Viewing consumed note](../../img/get-started/consumed-note.png) - - - Amazing! You just have created a client-side zero-knowledge proof locally on your machine and submitted it to the Miden rollup. - -!!! tip - You only need to copy the top line of characters of the Note ID. - -## View confirmations - -5. View your updated account's vault containing the tokens sent by the faucet by running the following command: - - ```shell - miden account --show - ``` - -6. You should now see your accounts vault containing the funds sent by the faucet. - - ![Viewing account vault with funds](../../img/get-started/view-account-vault.png) - -## Congratulations! - -You have successfully configured and used the Miden client to interact with a Miden rollup and faucet. - -You have performed basic Miden rollup operations like submitting proofs of transactions, generating and consuming notes. - -For more information on the Miden client, refer to the [Miden client documentation](https://docs.polygon.technology/miden/miden-client/). - -## Debugging tips (clear state and folder) - -- Need a fresh start? All state is maintained in `store.sqlite3`, located in the directory defined in the `miden-client.toml` file. If you want to clear all state, delete this file. It recreates on any command execution. - -- Getting an error? Only execute the `miden-client` command in the folder where your `miden-client.toml` is located. diff --git a/docs/introduction/get-started/p2p-private.md b/docs/introduction/get-started/p2p-private.md deleted file mode 100644 index 7755995b5..000000000 --- a/docs/introduction/get-started/p2p-private.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -comments: true ---- - -In this section, we show you how to make private transactions and send funds to another account using the Miden client. - -!!! important "Prerequisite steps" - - You should have already followed the [prerequisite steps](prerequisites.md) and [get started](create-account-use-faucet.md) documents. - - You should *not* have reset the state of your local client. - -## Create a second account - -!!! tip - Remember to use the [Miden client documentation](https://docs.polygon.technology/miden/miden-client/cli-reference/) for clarifications. - -1. Create a second account to send funds with. Previously, we created a type `mutable` account (account A). Now, create another `mutable` (account B) using the following command: - - ```shell - miden new-wallet --mutable - ``` - -2. List and view the newly created accounts with the following command: - - ```shell - miden account -l - ``` - -3. You should see two accounts: - - ![Result of listing miden accounts](../../img/get-started/two-accounts.png) - -## Transfer assets between accounts - -1. Now we can transfer some of the tokens we received from the faucet to our second account B. - - To do this, run: - - ```shell - miden send --sender --target --asset 50:: --note-type private - ``` - - !!! note - The faucet account id can be found on the [Miden faucet website](https://testnet.miden.io/) under the title **Miden faucet**. - - This generates a private Pay-to-ID (`P2ID`) note containing `50` assets, transferred from one account to the other. - -2. First, sync the accounts. - - ```shell - miden sync - ``` - -3. Get the second note id. - - ```sh - miden notes - ``` - -4. Have the second account consume the note. - - ```sh - miden consume-notes --account - ``` - - !!! tip - It's possible to use a short version of the note id: 7 characters after the `0x` is sufficient, e.g. `0x6ae613a`. - - You should now see both accounts containing faucet assets with amounts transferred from `Account A` to `Account B`. - -5. Check the second account: - - ```shell - miden account --show - ``` - - ![Result of listing miden accounts](../../img/get-started/account-b.png) - -6. Check the original account: - - ```sh - miden account --show - ``` - - ![Result of listing miden accounts](../../img/get-started/account-a.png) - -Wanna do more? [Sending public notes](p2p-public.md) - -## Congratulations! - -You have successfully configured and used the Miden client to interact with a Miden rollup and faucet. - -You have performed basic Miden rollup operations like submitting proofs of transactions, generating and consuming notes. - -For more information on the Miden client, refer to the [Miden client documentation](https://docs.polygon.technology/miden/miden-client/). - -## Clear data - -All state is maintained in `store.sqlite3`, located in the directory defined in the `miden-client.toml` file. - -To clear all state, delete this file. It recreates on any command execution. - -
diff --git a/docs/introduction/get-started/p2p-public.md b/docs/introduction/get-started/p2p-public.md deleted file mode 100644 index c191208c5..000000000 --- a/docs/introduction/get-started/p2p-public.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -comments: true ---- - -In this section, we show you how to execute transactions and send funds to another account using the Miden client and [public notes](https://docs.polygon.technology/miden/miden-base/architecture/notes/#note-storage-mode). - -!!! important "Prerequisite steps" - - You should have already followed the [prerequisite steps](prerequisites.md) and [get started](create-account-use-faucet.md) documents. - - You should have *not* reset the state of your local client. - -## Create a second client - -!!! tip - Remember to use the [Miden client documentation](https://docs.polygon.technology/miden/miden-client/cli-reference/) for clarifications. - -This is an alternative to the [private P2P transactions](p2p-private.md) process. - -In this tutorial, we use two different clients to simulate two different remote users who don't share local state. - -To do this, we use two terminals with their own state (using their own `miden-client.toml`). - -1. Create a new directory to store the new client. - - ```sh - mkdir miden-client-2 - cd miden-client-2 - ``` - -2. Initialize the client. This creates the `miden-client.toml` file line-by-line. - - ```sh - miden init --rpc 18.203.155.106 - ``` - For the `--rpc` flag, enter the IP that the Miden team supplied. - -3. On the new client, create a new [basic account](https://docs.polygon.technology/miden/miden-base/architecture/accounts/#account-types): - - ```shell - miden new-wallet --mutable -s public - ``` - - We refer to this account as _Account C_. Note that we set the account's storage mode to `public`, which means that the account details are public and its latest state can be retrieved from the node. - -4. List and view the account with the following command: - - ```shell - miden account -l - ``` - -## Transfer assets between accounts - -1. Now we can transfer some of the tokens we received from the faucet to our new account C. Remember to switch back to `miden-client` directory, since you'll be making the txn from Account ID A. - - To do this, from the first client run: - - ```shell - miden send --sender --target --asset 50:: --note-type public - ``` - - !!! note - The faucet account id is `0xad904b3138d71d3e` and can also be found on the [Miden faucet website](https://testnet.miden.io/) under the title **Miden faucet**. - - This generates a Pay-to-ID (`P2ID`) note containing `50` tokens, transferred from one account to the other. As the note is public, the second account can receive the necessary details by syncing with the node. - -2. First, sync the account on the new client. - - ```shell - miden sync - ``` - -3. At this point, we should have received the public note details. - - ```sh - miden notes --list - ``` - - Because the note was retrieved from the node, the commit height will be included and displayed. - -4. Have account C consume the note. - - ```sh - miden consume-notes --account - ``` - - !!! tip - It's possible to use a short version of the note id: 7 characters after the `0x` is sufficient, e.g. `0x6ae613a`. - -That's it! - -Account C has now consumed the note and there should be new assets in the account: - -```sh -miden account --show -``` - -## Clear state - -All state is maintained in `store.sqlite3`, located in the directory defined in the `miden-client.toml` file. - -To clear all state, delete this file. It recreates on any command execution. diff --git a/docs/introduction/get-started/prerequisites.md b/docs/introduction/get-started/prerequisites.md deleted file mode 100644 index 53d7b029b..000000000 --- a/docs/introduction/get-started/prerequisites.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -comments: true ---- - -This section shows you how to get started with Miden by generating a new Miden account, requesting funds from a public faucet, consuming private notes, and creating public pay-to-id-notes. - -By the end of this tutorial, you will have: - -- Configured the Miden client. -- Connected to a Miden node. -- Created an account and requested funds from the faucet. -- Transferred assets between accounts by creating and consuming notes. - -## Prerequisites - -### Rust - -Download from [the Rust website](https://www.rust-lang.org/learn/get-started). - -
\ No newline at end of file diff --git a/docs/introduction/roadmap.md b/docs/introduction/roadmap.md deleted file mode 100644 index a5cac714e..000000000 --- a/docs/introduction/roadmap.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -comments: true -hide: -- toc ---- - -![Roadmap](../img/roadmap.jpg) \ No newline at end of file diff --git a/docs/network/network.md b/docs/network/network.md index 774fbbc9c..ca8a2fb47 100644 --- a/docs/network/network.md +++ b/docs/network/network.md @@ -1,20 +1,16 @@ ---- -comments: true ---- - -!!! tip "Recap" - Polygon Miden network architecture contains a bi-directional token bridge and state machine. - - Miden nodes act as operators that maintain state and compress state transitions recursively into STARK-proofs. The token bridge on Ethereum verifies these proofs. - - Users can run Miden clients to send RPC requests to the Miden nodes to update the state. - - The major components of the Polygon Miden network are: - - - Miden clients which represent Miden users. - - Miden nodes which manage the Miden rollup and compress proofs. - - A verifier contract which maintains and verifies state on Ethereum. - - A bridge contract as an entry and exit point for users. +> **Tip: Recap** +> Polygon Miden network architecture contains a bi-directional token bridge and state machine. +> +> Miden nodes act as operators that maintain state and compress state transitions recursively into STARK-proofs. The token bridge on Ethereum verifies these proofs. +> +> Users can run Miden clients to send RPC requests to the Miden nodes to update the state. +> +> The major components of the Polygon Miden network are: +> +> - Miden clients which represent Miden users. +> - Miden nodes which manage the Miden rollup and compress proofs. +> - A verifier contract which maintains and verifies state on Ethereum. +> - A bridge contract as an entry and exit point for users. ## Overview of the Miden network @@ -22,21 +18,21 @@ comments: true ## Miden clients -Users run Miden clients and they provide an interface for wallets representing accounts on Miden. +Users run Miden clients and they provide an interface for wallets representing accounts on Miden. Miden clients can execute and prove transactions with the tx prover. They can handle arbitrary signature schemes. The default is [Falcon](https://falcon-sign.info/). There is a wallet user interface, a database that stores account data locally, and the required smart contract code that represents the account on Miden. ## Miden nodes -Operators run Miden nodes. +Operators run Miden nodes. -Operators ensure integrity of account, note, and nullifier states - all of which represent the state of Polygon Miden. Operators can execute and prove transactions against single accounts and they can also verify proofs of locally executed transactions. +Operators ensure integrity of account, note, and nullifier states - all of which represent the state of Polygon Miden. Operators can execute and prove transactions against single accounts and they can also verify proofs of locally executed transactions. Furthermore, the operator compresses the proofs in several steps up to a single proof that gets published and verified on the verifier contract. Operators also watch events emitted by the bridge contract to detect deposits and withdrawals. ### Node modules -To manage all of this, Miden nodes have separate modules. +To manage all of this, Miden nodes have separate modules. - Tx prover: Executes and proves transactions, like the Miden client. - Tx aggregator: Batches multiple proofs together to reduce the final state proof size using recursive proving. @@ -46,14 +42,14 @@ To manage all of this, Miden nodes have separate modules. This contract on Ethereum verifies proofs sent by the operator running a Miden Node. The proof is verified against the current state root. If accepted the state root changes. -!!! note - - Polygon Miden will integrate into the AggLayer. - - The specific design is not yet finalized. +> **Note** +> - Polygon Miden will integrate into the AggLayer. +> - The specific design is not yet finalized. ## Bridge contract This contract serves as a bridge for Miden users on Ethereum. Users can deposit their tokens and get an equivalent amount minted and sent to the specified address on Polygon Miden. -!!! note - - Polygon Miden will integrate into the AggLayer and the Unified Bridge. - - The specific design is not yet finalized. \ No newline at end of file +> **Note** +> - Polygon Miden will integrate into the AggLayer and the Unified Bridge. +> - The specific design is not yet finalized. diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 000000000..0f7a011f8 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1 @@ +![Roadmap](../img/roadmap.jpg) diff --git a/mkdocs.yml b/mkdocs.yml index 8c8a0cc46..20848c8de 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,12 +22,7 @@ theme: nav: - Welcome: index.md - - Get started: - - Prerequisite steps: introduction/get-started/prerequisites.md - - Create account and use the faucet: introduction/get-started/create-account-use-faucet.md - - Private peer-to-peer off-chain txs: introduction/get-started/p2p-private.md - - Public peer-to-peer note transactions: introduction/get-started/p2p-public.md - - Roadmap: introduction/roadmap.md + - Roadmap: roadmap.md - Miden architecture: - Overview: architecture/overview.md - Accounts: architecture/accounts.md