-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(yellowpaper): first draft of avm circuit memory (#3865)
- Loading branch information
Showing
2 changed files
with
57 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
--- | ||
sidebar_position: 2 | ||
--- | ||
|
||
# Instruction Set | ||
|
||
import GeneratedInstructionSet from './gen/_InstructionSet.mdx'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# AVM Circuit | ||
|
||
## Memory | ||
To process a public execution request, the AVM executes the request's initial message call along with any nested calls it encounters. Execution of a message call requires some context including an `ExecutionEnvironment` and `MachineState`. Separate instances of these constructs must exist for each message call. | ||
|
||
AVM instructions may read from or write to these constructs (explicitly or indirectly), and therefore it is natural to represent them in the AVM circuit via a memory table. Since each call must have its own `ExecutionEnvironment` and `MachineState`, each entry in the memory table must specify which call it corresponds to. This is accomplished via a `callPointer` column. The memory table is sorted first by `callPointer` and thus all memory accesses for a given message call are grouped. | ||
|
||
User code has explicit access to a construct known as **user memory**, also known as `MachineState.memory`. When an AVM instruction performs an access like `M[offset]`, it is accessing user memory. | ||
|
||
The remainder of a call's `ExecutionEnvironment` and `MachineState` is not explicitly addressable by user code. This remaining context lives in a construct known as **protected memory** and is accessible only via dedicated instructions (like `ADDRESS`, `JUMP`, `CALL`, etc...). | ||
|
||
> Note: the fact that this context is implemented as protected circuit memory is not relevant to user code or even to the high-level AVM specification. | ||
Therefore, for a given call the VM circuit's memory table is subdivided into user and protected memories. This is accomplished via a `userMemory` column which flags each of a call's memory table entries as either a user or protected memory access. | ||
|
||
The VM circuit's memory is sorted first by `callPointer` and next by the `userMemory` flag (before standard sorting by memory address, timestamp, etc...). Thus, the memory table is organized as follows: | ||
- VM circuit memory | ||
- call `0` memory | ||
- protected memory | ||
- user memory | ||
- call `1` memory | ||
- protected memory | ||
- user memory | ||
- ... | ||
- call `n-1` memory | ||
- protected memory | ||
- user memory | ||
|
||
### Protected memory offsets | ||
As mentioned above, a call's `ExecutionEnvironment` and `MachineState` (except for `MachineState.memory`) reside in protected memory, and so each of their members has a dedicated offset. These offsets are referred to according to the following pattern: | ||
- `ENVIRONMENT_ADDRESS_OFFSET`: offset to `ExecutionEnvironment.address` within a call's protected memory subregion | ||
- `ENVIRONMENT_L1GASPRICE`: offset to `ExecutionEnvironment.l1GasPrice` within a call's protected memory subregion | ||
- `MACHINESTATE_L1GASLEFT`: offset to `MachineState.l1GasLeft` within a call's protected memory subregion | ||
- `MACHINESTATE_PC`: offset to `MachineState.pc` within a call's protected memory subregion | ||
- `MACHINESTATE_INTERNALCALLSTACK`: offset to `MachineState.internalCallStack` within a call's protected memory subregion | ||
|
||
> Note: A call's `ExecutionEnvironment.bytecode` and `ExecutionEnvironment.calldata` are not included in the protected memory region because they are handled in a special manner. This will be expanded on in a later section. | ||
> For complete definitions of `ExecutionEnvironment` and `MachineState` see the [AVM's high level specification](./avm.md). | ||
### Protected memory and user memory examples | ||
An instruction like `ADDRESS` serves as great example because it performs a read from protected memory and a write to user memory: `M[dstOffset] = ExecutionEnvironment.address` (see [Instruction Set](./InstructionSet) for more details). Below, this operation is deconstructed into its two memory accesses: | ||
1. `ExecutionEnvironment.address` | ||
- memory read | ||
- flags: `callPointer`, `userMemory = 0` (protected memory access) | ||
- offset: `ENVIRONMENT_ADDRESS_OFFSET` | ||
1. `M[dstOffset] =` | ||
- memory write | ||
- flags: `callPointer`, `userMemory = 1` (user memory access) | ||
- offset: `dstOffset` |