diff --git a/docs/architecture/accounts.md b/docs/architecture/account.md similarity index 91% rename from docs/architecture/accounts.md rename to docs/architecture/account.md index 8f972047d..082b11fff 100644 --- a/docs/architecture/accounts.md +++ b/docs/architecture/account.md @@ -1,15 +1,11 @@ # Account -> The primary entity of the Miden protocol +An `Account` represents the primary entity of the protocol. Capable of holding assets, storing data, and executing custom code. Each `Account` is a specialized smart contract providing a programmable interface for interacting with its state and assets. ## What is the purpose of an account? In Miden's hybrid UTXO and account-based model `Account`s enable the creation of expressive smart contracts via a Turing-complete language. -## What is an account? - -In Miden, an `Account` represents an entity capable of holding assets, storing data, and executing custom code. Each `Account` is a specialized smart contract providing a programmable interface for interacting with its state and managed assets. - ## Account core components An `Account` is composed of several core components, illustrated below: @@ -117,7 +113,3 @@ Users can choose whether their `Account`s are stored publicly or privately. The Only a commitment (hash) to the `Account`’s state is stored on-chain. This mode is suitable for users who prioritize privacy or plan to store a large amount of data in their `Account`. To interact with a private `Account`, a user must have knowledge of its interface. The storage mode is chosen during `Account` creation, it cannot be changed later. - -## Conclusion - -You are now better equipped to understand how a Miden `Account` operates, how it manages data and assets, and how its programmable interface enables secure and flexible interactions within the Miden protocol. diff --git a/docs/architecture/assets.md b/docs/architecture/asset.md similarity index 84% rename from docs/architecture/assets.md rename to docs/architecture/asset.md index ead9d193a..dcd886995 100644 --- a/docs/architecture/assets.md +++ b/docs/architecture/asset.md @@ -1,6 +1,6 @@ # Asset -> Fungible and Non-fungible assets in the Miden protocol. +An `Asset` is a unit of value that can be transferred from one [account](accounts.md) to another using [notes](notes.md). ## What is the purpose of an asset? @@ -18,10 +18,6 @@ In Miden, `Asset`s serve as the primary means of expressing and transferring val 4. **Flexible fee payment:** Unlike protocols that require a specific base `Asset` for fees, Miden allows users to pay fees in any supported `Asset`. This flexibility simplifies the user experience. -## What is an asset? - -An `Asset` in Miden is a unit of value that can be transferred from one [account](accounts.md) to another using [notes](notes.md). - ## Native asset > All data structures following the Miden asset model that can be exchanged. @@ -62,7 +58,3 @@ Non-fungible `Asset`s are encoded by hashing the `Asset` data into 32 bytes and > All data structures not following the Miden asset model that can be exchanged. Miden is flexible enough to support other `Asset` models. For example, developers can replicate Ethereum’s ERC20 pattern, where fungible `Asset` ownership is recorded in a single account. To transact, users send a note to that account, triggering updates in the global hashmap state. - -## Conclusion - -Miden’s `Asset` model provides a secure, flexible, scalable, and privacy-preserving framework for representing and transferring value. By embedding `Asset` information directly into accounts and supporting multiple `Asset` types, Miden fosters a decentralized ecosystem where users maintain their privacy, control, transactions can scale efficiently, and censorship is minimized. diff --git a/docs/architecture/notes.md b/docs/architecture/note.md similarity index 91% rename from docs/architecture/notes.md rename to docs/architecture/note.md index f482f73be..c25830e5f 100644 --- a/docs/architecture/notes.md +++ b/docs/architecture/note.md @@ -1,15 +1,11 @@ # Note -> The medium through which [Accounts](accounts.md) communicate in the Miden protocol. +A `Note` is the medium through which [Accounts](accounts.md) communicate. A `Note` holds assets and defines how they can be consumed. ## What is the purpose of a note? In Miden's hybrid UTXO and account-based model `Note`s represent UTXO's which enable parallel transaction execution and privacy through asynchronous local `Note` production and consumption. -## What is a note? - -A `Note` in Miden holds assets and defines how these assets can be consumed. - ## Note core components A `Note` is composed of several core components, illustrated below: @@ -135,7 +131,3 @@ 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) - -## Conclusion - -Miden’s `Note` introduce a powerful mechanism for secure, flexible, and private state management. By enabling asynchronous asset transfers, parallel execution, and privacy at scale, `Note`s transcend the limitations of strictly account-based models. As a result, developers and users alike enjoy enhanced scalability, confidentiality, and control. With these capabilities, Miden is paving the way for true **programmable money** where assets, logic, and trust converge seamlessly. diff --git a/docs/architecture/state.md b/docs/architecture/state.md index 8f4294318..b8843c7ee 100644 --- a/docs/architecture/state.md +++ b/docs/architecture/state.md @@ -1,6 +1,6 @@ # State -> The snapshot of all accounts, notes, nullifiers and their statuses in Miden, reflecting the “current reality” of the protocol at any given time. +The `State` describes the current condition of all accounts, notes, nullifiers and their statuses. Reflecting the “current reality” of the protocol at any given time. ## What is the purpose of the Miden state model? @@ -17,10 +17,6 @@ Miden’s `State` model focuses on: - **Privacy:** By using notes and nullifiers, Miden ensures that value transfers remain confidential. Zero-knowledge proofs allow users to prove correctness without revealing sensitive information. -## What is state? - -The `State` of the Miden rollup describes the current condition of all accounts and notes in the protocol; i.e., the current reality. - ## State model components The Miden node maintains three databases to describe `State`: @@ -117,7 +113,3 @@ In this diagram, multiple participants interact with a common, publicly accessib Miden nodes do not need to know the entire `State` to verify or produce new blocks. Rather than storing the full `State` data with the nodes, users keep their data locally, and the rollup stores only commitments to that data. While some contracts must remain publicly visible, this approach minimizes `State` bloat. Furthermore the Miden rollup can discard non-required data after certain conditions have been met. This ensures that the account and note databases remain manageable, even under sustained high usage. - -## Conclusion - -Miden’s `State` model lays the foundation for a scalable, privacy-preserving, and user-centric environment. By combining parallelizable execution, flexible data storage, and Zero-knowledge proofs that ensure integrity and confidentiality, Miden addresses many of the challenges of traditional blockchains. As a result, the network can handle high throughput, maintain manageable `State` sizes, and support a wide range of applications. diff --git a/docs/architecture/transaction.md b/docs/architecture/transaction.md new file mode 100644 index 000000000..078e33ff1 --- /dev/null +++ b/docs/architecture/transaction.md @@ -0,0 +1,137 @@ +# Transaction + +A `Transaction` in Miden is the state transition of a single account. A `Transaction` takes as input a single [account](accounts.md) and zero or more [notes](notes.md), and outputs the same account with an updated state, together with zero or more notes. `Transaction`s in Miden are Miden VM programs, their execution resulting in the generation of a zero-knowledge proof. + +Miden's `Transaction` model aims for the following: + +- **Parallel transaction execution**: Accounts can update their state independently from each other and in parallel. +- **Private transaction execution**: Client-side `Transaction` proving allows the network to verify `Transaction`s validity with zero knowledge. + +![Transaction diagram](../img/architecture/transaction/transaction-diagram.png) + +Compared to most blockchains, where a `Transaction` typically involves more than one account (e.g., sender and receiver), a `Transaction` in Miden involves a single account. To illustrate, Alice sends 5 ETH to Bob. In Miden, sending 5 ETH from Alice to Bob takes two `Transaction`s, one in which Alice creates a note containing 5 ETH and one in which Bob consumes that note and receives the 5 ETH. This model removes the need for a global lock on the blockchain's state, enabling Miden to process `Transaction`s in parallel. + +Currently the protocol limits the number of notes that can be consumed and produced in a transaction to 1000 each, which means that in a single `Transaction` an application could serve up to 2000 different user requests like deposits or withdrawals into/from a pool. + +A simple transaction currently takes about 1-2 seconds on a MacBook Pro. It takes around `90K` cycles to create the proof, as of now the signature verification step is the dominant cost. + +## Transaction lifecycle + +Every `Transaction` describes the process of an account changing its state. This process is described as a Miden VM program, resulting in the generation of a zero-knowledge proof. `Transaction`s are being executed in a specified sequence, in which several notes and a transaction script can interact with an account. + +![Transaction execution flow](../img/architecture/transaction/transaction-program.png) + +### Inputs + +A `Transaction` requires several inputs: + +- **Account**: A `Transaction` is always executed against a single account. The executor must have complete knowledge of the account's state. + +- **Notes**: A `Transaction` can consume up to `1K` notes. The executor must have complete knowledge of the note data, including note inputs, before consumption. For private notes, the data cannot be fetched from the blockchain and must be received through an off-chain channel. + +- **Blockchain state**: The current reference block and information about the notes database used to authenticate notes to be consumed must be retrieved from the Miden operator before execution. Usually, notes to be consumed in a `Transaction` must have been created before the reference block. + +- **Transaction script (optional)**: `Transaction` scripts are defined by the executor. And like note scripts, they can invoke account methods, e.g., sign a transaction. + +- **Transaction arguments (optional)**: For every note, the executor can inject transaction arguments that are present at runtime. If the note script — and therefore the note creator — allows, the note script can read those arguments to allow dynamic execution. See below for an example. + +- **Foreign account data (optional)**: Any foreign account data accessed during a `Transaction`, whether private or public, must be available beforehand. There is no need to know the full account storage, but the data necessary for the `Transaction`, e.g., the key/value pair that is read and the corresponding storage root. + +### Flow + +1. **Prologue** + + Executes at the beginning of a transaction. It validates on-chain commitments against the provided data. This is to ensure that the transaction executes against a valid on-chain recorded state of the account and to be consumed notes. Notes to be consumed must be registered on-chain — except for [ephemeral notes](note.md) which can be consumed without block inclusion. + +2. **Note processing** + + Notes are executed sequentially against the account, following a sequence defined by the executor. To execute a note means processing the note script that calls methods exposed on the account interface. Notes must be consumed fully, which means that all assets must be transferred into the account or into other created notes. [Note scripts](note.md/script) can invoke the account interface during execution. They can push assets into the account's vault, create new notes, set a transaction expiration, and read from or write to the account’s storage. Any method they call must be explicitly exposed by the account interface. Note scripts can also invoke methods of foreign accounts to read their state. + +3. **Transaction script processing** + + `Transaction` scripts are an optional piece of code defined by the executor which interacts with account methods after all notes have been executed. For example, `Transaction` scripts can be used to sign the `Transaction` (e.g., sign the transaction by incrementing the nonce of the account, without which, the transaction would fail), to mint tokens from a faucet, create notes, or modify account storage. `Transaction` scripts can also invoke methods of foreign accounts to read their state. + +4. **Epilogue** + + Completes the execution, resulting in an updated account state and a generated zero-knowledge proof. The validity of the resulting state change is checked. The account's `Nonce` must have been incremented, which is how the entire transaction is authenticated. Also, the net sum of all involved assets must be `0` (if the account is not a faucet). + +The proof together with the corresponding data needed for verification and updates of the global state can then be submitted and processed by the network. + +## Examples + +To illustrate the `Transaction` protocol, we provide two examples for a basic `Transaction`. We will use references to the existing Miden `Transaction` kernel — the reference implementation of the protocol — and to the methods in Miden Assembly. + +### Creating a P2ID note + +Let's assume account A wants to create a P2ID note. P2ID notes are pay-to-ID notes that can only be consumed by a specified target account ID. Note creators can provide the target account ID using the [note inputs](note.md). + +In this example, account A uses the basic wallet and the authentication component provided by `miden-lib`. The basic wallet component defines the methods `wallets::basic::create_note` and `wallets::basic::move_asset_to_note` to create notes with assets, and `wallets::basic::receive_asset` to receive assets. The authentication component exposes `auth::basic::auth_tx_rpo_falcon512` which allows for signing a transaction. Some account methods like `account::get_id` are always exposed. + +The executor inputs to the Miden VM a `Transaction` script in which he places on the stack the data (tag, aux, note_type, execution_hint, RECIPIENT) of the note(s) that he wants to create using `wallets::basic::create_note` during the said `Transaction`. The [`NoteRecipient`](https://github.com/0xPolygonMiden/miden-base/blob/main/crates/miden-objects/src/note/recipient.rs) is a value that describes under which condition a note can be consumed and is built using a `serial_number`, the `note_script` (in this case P2ID script) and the `note_inputs`. The Miden VM will execute the `Transaction` script and create the note(s). After having been created, the executor can use `wallets::basic::move_asset_to_note` to move assets from the account's vault to the notes vault. + +After finalizing the `Transaction` the updated state and created note(s) can now be submitted to the Miden operator to be recorded on-chain. + +### Consuming a P2ID note + +Let's now assume that account A wants to consume a P2ID note to receive the assets contained in that note. + +To start the transaction process, the executor fetches and prepares all the input data to the `Transaction`. First, it retrieves blockchain data, like global inputs and block data of the most recent block. This information is needed to authenticate the native account's state and that the P2ID note exists on-chain. Then it loads the full account and note data, to start the `Transaction` execution. + +In the transaction's prologue the data is being authenticated by re-hashing the provided values and comparing them to the blockchain's data (this is how private data can be used and verified during the execution of transaction without actually revealing it to the network). + +Then the P2ID note script is being executed. The script starts by reading the note inputs `note::get_inputs` — in our case the account ID of the intended target account. It checks if the provided target account ID equals the account ID of the executing account. This is the first time the note invokes a method exposed by the `Transaction` kernel, `account::get_id`. + +If the check passes, the note script pushes the assets it holds into the account's vault. For every asset the note contains, the script calls the `wallets::basic::receive_asset` method exposed by the account's wallet component. The `wallets::basic::receive_asset` procedure calls `account::add_asset`, which cannot be called from the note itself. This allows accounts to control what functionality to expose, e.g. whether the account supports receiving assets or not, and the note cannot bypass that. + +After the assets are stored in the account's vault, the transaction script is being executed. The script calls `auth::basic::auth_tx_rpo_falcon512` which is explicitly exposed in the account interface. The method is used to verify a provided signature against a public key stored in the account's storage and a commitment to this specific transaction. If the signature can be verified, the method increments the nonce. + +The Epilogue finalizes the transaction by computing the final account hash, asserting the nonce increment and checking that no assets were created or destroyed in the transaction — that means the net sum of all assets must stay the same. + +## Transaction types + +There are two types of `Transaction`s in Miden: **local transactions** and **network transactions** [not yet implemented]. + +### Local transaction + +Users transition their account's state locally using the Miden VM and generate a `Transaction` proof that can be verified by the network, which we call **client-side proving**. The network then only has to verify the proof and to change the global parts of the state to apply the state transition. + +They are useful, because: + +1. They enable privacy as neither the account state nor account code are needed to verify the zero-knowledge proof. Public inputs are only commitments and block information that are stored on-chain. +2. They are cheaper (i.e., lower in fees) as the execution of the state transition and the generation of the zero-knowledge proof are already made by the users. Hence **privacy is the cheaper option on Miden**. +3. They allow arbitrarily complex computation to be done. The proof size doesn't grow linearly with the complexity of the computation. Hence there is no gas limit for client-side proving. + +Client-side proving or local transactions on low-power devices can be slow, but Miden offers a pragmatic alternative: **delegated proving**. Instead of waiting for complex computations to finish on your device, you can hand off proof generation to a service, ensuring a consistent 1-2 second proving time, even on mobile. + +### Network transaction + +The Miden operator executes the `Transaction` and generates the proof. Miden uses network `Transaction`s for smart contracts with public shared state. This type of `Transaction` is quite similar to the ones in traditional blockchains (e.g., Ethereum). + +They are useful, because: + +1. For public shared state of smart contracts. Network `Transaction`s allow orchestrated state changes of public smart contracts without race conditions. +2. Smart contracts should be able to be executed autonomously, ensuring liveness. Local `Transaction`s require a user to execute and prove, but in some cases a smart contract should be able to execute when certain conditions are met. +3. Clients may not have sufficient resources to generate zero-knowledge proofs. + +The ability to facilitate both, local and network `Transaction`s, **is one of the differentiating factors of Miden** compared to other blockchains. Local `Transaction` execution and proving can happen in parallel as for most `Transaction`s there is no need for public state changes. This increases the network's throughput tremendously and provides privacy. Network `Transaction`s on the other hand enable autonomous smart contracts and public shared state. + +--- + +> **Good to know** +> +> - Usually, notes that are consumed in a `Transaction` must be recorded on-chain in order for the `Transaction` to succeed. However, Miden supports **ephemeral notes** which are notes that can be consumed in a `Transaction` before being registered on-chain. For example, one can build a sub-second order book by allowing its traders to build faster transactions that depend on each other and are being validated or erased in batches. +> +> - There is no nullifier check during a `Transaction`. Nullifiers are checked by the Miden operator during `Transaction` verification. So at the local level, there is "double spending." If a note was already spent, i.e. there exists a nullifier for that note, the block producer would never include the `Transaction` as it would make the block invalid. +> +> - One of the main reasons for separating 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. +> +> - Not all `Transaction`s require notes. For example, the owner of a faucet can mint new tokens using only a `Transaction` script, without interacting with external notes. +> +> - In Miden executors can choose arbitrary reference blocks to execute against their state. Hence it is possible to set `Transaction` expiration heights and in doing so, to define a block height until a `Transaction` should be included into a block. If the `Transaction` is expired, the resulting account state change is not valid and the `Transaction` cannot be verified anymore. +> +> - Note and `Transaction` scripts can read the state of foreign accounts during execution. This is called foreign procedure invocation. For example, the price of an asset for the **Swap** script might depend on a certain value stored in the oracle account. +> +> - An example of the right usage of `Transaction` arguments is the consumption of a **Swap** note. Those notes allow asset exchange based on predefined conditions. Example: +> - The note's consumption condition is defined as "anyone can consume this note to take `X` units of asset A if they simultaneously create a note sending Y units of asset B back to the creator." If an executor wants to buy only a fraction `(X-m)` of asset A, they provide this amount via transaction arguments. The executor would provide the value `m`. The note script then enforces the correct transfer: +> - A new note is created returning `Y-((m*Y)/X)` of asset B to the sender. +> - A second note is created, holding the remaining `(X-m)` of asset A for future consumption. diff --git a/docs/architecture/transactions/contexts.md b/docs/architecture/transactions/contexts.md deleted file mode 100644 index ce3a0e4ff..000000000 --- a/docs/architecture/transactions/contexts.md +++ /dev/null @@ -1,84 +0,0 @@ -## 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. - -## 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 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. - -```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. -# ... -begin - - ... - - exec.add_note_assets_to_account - # => [...] -end -``` - -The procedure cannot simply add assets to the account, because it is executed in a note context. Therefore, it needs to `call` the account interface. This moves execution into a second context - account context - isolated from the note context **(2)**. - -```arduino -#! Helper procedure to add all assets of a note to an account. -#! ... -proc.add_note_assets_to_account - ... - - while.true - ... - - # load the asset - mem_loadw - # => [ASSET, ptr, end_ptr, ...] - - # pad the stack before call - padw swapw padw padw swapdw - # => [ASSET, pad(12), ptr, end_ptr, ...] - - # add asset to the account - call.wallet::receive_asset - # => [pad(16), ptr, end_ptr, ...] - - # clean the stack after call - dropw dropw dropw - # => [0, 0, 0, 0, ptr, end_ptr, ...] - ... - end - ... -end -``` - -The [wallet](https://github.com/0xPolygonMiden/miden-base/blob/main/miden-lib/asm/miden/contracts/wallets/basic.masm) smart contract provides an interface that accounts use to receive and send assets. In this new context, the wallet calls the `add_asset` procedure of the account API. - -```arduino -export.receive_asset - exec.account::add_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, 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. -#! ... -export.add_asset - exec.kernel_proc_offsets::account_add_asset_offset - syscall.exec_kernel_proc -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 deleted file mode 100644 index d8f746fc5..000000000 --- a/docs/architecture/transactions/execution.md +++ /dev/null @@ -1,45 +0,0 @@ -The Miden transaction executor is the component that executes transactions. - -Transaction execution consists of the following steps and results in an `ExecutedTransaction` object: - -1. Fetch the data required to execute a transaction from the data store. -2. Compile the transaction into an executable [MASM](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/main.html) program using the transaction compiler. -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. - -## Data store and transaction inputs - -The data store defines the interface that transaction objects use to fetch the data for transaction executions. Specifically, it provides the following inputs to the transaction: - -- `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. - -> **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 - -Every transaction is executed within the Miden VM to generate a transaction proof. In Miden, there is a proof for every transaction. - -The transaction compiler is responsible for building executable programs. The generated MASM programs can then be executed by the Miden VM which generates a zk-proof. In addition to transaction compilation, the transaction compiler provides methods for compiling Miden account code, note scripts, and transaction scripts. - -Compilation results in an executable MASM program. The program includes the provided account interface and notes, an optional transaction script, and the [transaction kernel program](kernel.md). The transaction kernel program defines procedures and the memory layout for all parts of the transaction. - -After compilation, assuming correctly-populated inputs, including the advice provider, the transaction can be executed. - -## 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. - -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 deleted file mode 100644 index f6e55d1cf..000000000 --- a/docs/architecture/transactions/kernel.md +++ /dev/null @@ -1,121 +0,0 @@ -# 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 a MASM [kernel](https://0xpolygonmiden.github.io/miden-vm/user_docs/assembly/execution_contexts.html#kernels). - -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. - -> **Info** -> - Learn more about Miden transaction [procedures](procedures.md) and [contexts](contexts.md). - -The kernel has a well-defined structure which does the following: - -1. The [prologue](#prologue) prepares the transaction for processing by parsing the transaction data and setting up the root context. -2. Note processing executes the note processing loop which consumes each `InputNote` and invokes the note script of each note. -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`. - -- **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: - -1. _Unhashes_ the inputs and lays them out in the root context memory. -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. - -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 - -Tracks variables used internally by the transaction kernel. - -### Global inputs - -Stored in pre-defined memory slots. Global inputs include the block hash, account ID, initial account hash, and nullifier commitment. - -### Block data - -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 root is recomputed and verified against the chain root in the block data section. - -### Account data - -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 - -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. - -> **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. - -## Note Processing - -Notes are consumed in a loop, invoking their scripts in isolated contexts using `dyncall`. - -```arduino -# 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 may be triggered, and information about the new note is stored in the output note data. - -> **Info** -> - Notes can only call account interfaces to trigger write operations, preventing direct access to account storage. - -## Transaction Script Processing - -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 - -begin - padw padw padw padw - call.auth_tx::auth_tx_rpo_falcon512 - dropw dropw dropw dropw -end -``` - -> **Note** -> - The account must expose the `auth_tx_rpo_falcon512` function for the transaction script to call it. - -## Epilogue - -Finalizes the transaction: - -1. Computes the final account hash. -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 input and output vault roots are equal (except for special accounts like faucets). - -## Outputs - -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 deleted file mode 100644 index c3fc4d103..000000000 --- a/docs/architecture/transactions/overview.md +++ /dev/null @@ -1,79 +0,0 @@ -# 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. - -

- Transactions architecture overview -

- -> **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 - -Transactions in Miden facilitate single account state changes. Miden requires two transactions to transfer assets between accounts. - -A transaction takes a single account and some [notes](../notes.md) as input, and outputs the same account with a new state, together with some other notes. - -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. - -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. - -## 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`. - -### Asynchronous execution - -Both transactions can be executed asynchronously: first `transaction1` is executed, and then, some time later, `transaction2` is executed. - -This opens up a few interesting possibilities: - -- 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 - -This is where clients executing the transactions also generate the proofs of their correct execution. So, no additional work needs to be performed by the network. - -Local transactions are useful for several reasons: - -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. - -### Network transactions - -This is where the operator executes the transaction and generates the proofs. - -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. diff --git a/docs/architecture/transactions/procedures.md b/docs/architecture/transactions/procedures.md deleted file mode 100644 index 9942b1782..000000000 --- a/docs/architecture/transactions/procedures.md +++ /dev/null @@ -1,76 +0,0 @@ -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`. - -### Account - -To import the account procedures, set `use.miden::account` at the beginning of the file. - -Any procedure that changes the account state must be invoked in the account context and not by note or transaction scripts. All procedures invoke `syscall` to the kernel API and some are restricted by the kernel procedure `exec.authenticate_account_origin`, which fails if the parent context is not the executing account. - -| Procedure name | Stack | Output | Context | Description | -| ------------------------ | ------------------- | ------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `get_id` | `[]` | `[acct_id]` | account, note | | -| `get_nonce` | `[]` | `[nonce]` | account, note | | -| `get_initial_hash` | `[]` | `[H]` | account, note | | -| `get_current_hash` | `[]` | `[ACCT_HASH]` | account, note | | -| `incr_nonce` | `[value]` | `[]` | account | | -| `get_item` | `[index]` | `[VALUE]` | account, note | | -| `set_item` | `[index, V']` | `[R', V]` | account | | -| `set_code` | `[CODE_COMMITMENT]` | `[]` | account | | -| `get_balance` | `[faucet_id]` | `[balance]` | account, note | | -| `has_non_fungible_asset` | `[ASSET]` | `[has_asset]` | account, note | | -| `add_asset` | `[ASSET]` | `[ASSET']` | account | | -| `remove_asset` | `[ASSET]` | `[ASSET]` | account | | -| `get_vault_commitment` | `[]` | `[COM]` | account, note | | - -### Note - -To import the note procedures, set `use.miden::note` at the beginning of the file. All procedures are restricted to the note context. - -| Procedure name | Inputs | Outputs | Context | Description | -| --------------------- | -------------------------- | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `get_assets` | `[dest_ptr]` | `[num_assets, dest_ptr]` | note | | -| `get_inputs` | `[dest_ptr]` | `[dest_ptr]` | note | | -| `get_sender` | `[]` | `[sender]` | note | | -| `compute_inputs_hash` | `[inputs_ptr, num_inputs]` | `[HASH]` | note | | -| `get_note_serial_number`| `[]` | `[SERIAL_NUMBER]` | note | | -| `get_script_hash` | `[]` | `[SCRIPT_HASH]` | note | | - -### Tx - -To import the transaction procedures set `use.miden::tx` at the beginning of the file. Only the `create_note` procedure is restricted to the account context. - -| Procedure name | Inputs | Outputs | Context | Description | -| ----------------------- | ------------------------- | ------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `get_block_number` | `[]` | `[num]` | account, note |