Skip to content

Commit

Permalink
docs(yellowpaper): refresh of avm instruction set (#4081)
Browse files Browse the repository at this point in the history
- Misc cleanup
- Recategorized and *reordered* instructions
- Updated instruction expressions to match context structure in
high-level spec
- Removed opcode numbers from section titles as it makes links ugly
- Removed opcode numbers from images so they don't need to be
regenerated for now
- `in-tag` -> `inTag`, same with `dstTag`
- Intro Instruction Set section with some relevant notes
- Removed misc `*ROOT` opcodes in favor of `BLOCKHEADERBYNUM` opcode
- Cleanup in high-level avm spec
  • Loading branch information
dbanks12 authored Jan 18, 2024
1 parent 52a9327 commit 52162ee
Show file tree
Hide file tree
Showing 75 changed files with 1,217 additions and 1,281 deletions.
101 changes: 54 additions & 47 deletions yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,84 @@
/**
* All avm opcodes
* All AVM opcodes
*/
export enum Opcodes {
// Arithmetic
// Compute
// Compute - Arithmetic
ADD,
SUB,
MUL,
DIV,
// Compute - Comparators
EQ,
LT,
LTE,
// Compute - Bitwise
AND,
OR,
XOR,
NOT,
SHL,
SHR,
// Compute - Type Conversions
CAST,
// Memory
SET,
MOV,
CMOV,
CALLDATACOPY,

// Logs
EMITNOTEHASH,
EMITNULLIFIER,
SENDL2TOL1MSG,
ULOG,
// Control flow
JUMP,
JUMPI,
INTERNALCALL,
INTERNALRETURN,

// Storage
SLOAD,
SSTORE,
// Contract call control flow
RETURN,
REVERT,
CALL,
STATICCALL,

// Execution Environment
ADDRESS,
STORAGEADDRESS,
ORIGIN,
SENDER,
PORTAL,
FEEPERL1GAS,
FEEPERL2GAS,
FEEPERDAGAS,
CONTRACTCALLDEPTH,
// Execution Environment - Globals
CHAINID,
VERSION,
BLOCKNUMBER,
TIMESTAMP,
COINBASE,
BLOCKL1GASLIMIT,
BLOCKL2GASLIMIT,
NULLIFIERSOOT,
CONTRACTSROOT,
MSGSROOT,
NOTESROOT,
PUBLICDATAROOT,
GLOBALSHASH,
BLOCKSROOT,
GRANDROOT,
BLOCKDAGASLIMIT,
// Execution Environment - Calldata
CALLDATACOPY,

// Call context
ORIGIN,
REFUNDEE,
FEEPERL1GAS,
FEEPERL2GAS,
CALLER,
ADDRESS,
PORTAL,
CALLDEPTH,
l1GAS,
L2GAS,
// Machine State
// Machine State - Gas
L1GASLEFT,
L2GASLEFT,
DAGASLEFT,
// Machine State - Internal Control Flow
JUMP,
JUMPI,
INTERNALCALL,
INTERNALRETURN,
INTERNALCALLDEPTH,
// Machine State - Memory
SET,
MOV,
CMOV,

// World State
BLOCKHEADERBYNUMBER,
SLOAD, // Public Storage
SSTORE, // Public Storage
READL1TOL2MSG, // Messages
SENDL2TOL1MSG, // Messages
EMITNOTEHASH, // Notes & Nullifiers
EMITNULLIFIER, // Notes & Nullifiers

// Accrued Substate
EMITUNENCRYPTEDLOG,

// Control Flow - Contract Calls
CALL,
STATICCALL,
RETURN,
REVERT,

// Black box
// Gadgets
KECCAK,
POSEIDON,
}
55 changes: 26 additions & 29 deletions yellow-paper/docs/public-vm/avm.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A **caller** is a contract call's initiator. The caller of an initial contract c

- [**Public contract bytecode**](#public-contract-bytecode) (aka AVM bytecode)
- [**Execution context**](#execution-context), outlining the AVM's environment and state
- [**Execution**](#execution), outlining control flow, gas tracking, halting, and reverting
- [**Execution**](#execution), outlining control flow, gas tracking, normal halting, and exceptional halting
- [**Initial contract calls**](#initial-contract-calls), outlining the initiation of a contract call from a public execution request
- [**Nested contract calls**](#nested-contract-calls), outlining the initiation of a contract call from an instruction as well as the processing of nested execution results, gas refunds, and state reverts

Expand Down Expand Up @@ -69,14 +69,13 @@ ExecutionEnvironment {
address: AztecAddress,
storageAddress: AztecAddress,
origin: AztecAddress,
l1GasPrice: field,
l2GasPrice: field,
daGasPrice: field,
sender: AztecAddress,
portal: AztecAddress,
blockHeader: BlockHeader,
globalVariables: PublicGlobalVariables,
feePerL1Gas: field,
feePerL2Gas: field,
feePerDaGas: field,
contractCallDepth: field,
globals: PublicGlobalVariables,
isStaticCall: boolean,
isDelegateCall: boolean,
calldata: [field; <calldata-length>],
Expand All @@ -95,7 +94,7 @@ MachineState {
daGasLeft: field,
pc: field = 0,
internalCallStack: Vector<field> = [], // initialized as empty
memory: [field; 32768] = [0, ..., 0], // all 32768 (2^32) entries are initialized to zero
memory: [field; 2^32] = [0, ..., 0], // all 2^32 entries are initialized to zero
}
```

Expand All @@ -121,7 +120,7 @@ WorldState {
contracts: AztecAddress => {bytecode, portalAddress}, // read-only from within AVM
blockHeaders: Vector<BlockHeader>, // read-only from within AVM
publicStorage: (AztecAddress, field) => value, // read/write
l1ToL2Messages: (AztecAddress, field) => message, // read-only from within AVM
l1ToL2Messages: field => message, // read-only from within AVM
l2ToL1Messages: Vector<[field; <msg-length>]>, // append-only (no reads) from within AVM
noteHashes: Vector<field>, // append-only (no reads) from within AVM
nullifiers: Vector<field>, // append-only (no reads) from within AVM
Expand Down Expand Up @@ -217,7 +216,7 @@ machineState.daGasLeft = 0

An instruction's gas cost is meant to reflect the computational cost of generating a proof of its correct execution. For some instructions, this computational cost changes based on inputs. Here are some examples and important notes:
- [`JUMP`](./instruction-set/#isa-section-jump) is an example of an instruction with constant gas cost. Regardless of its inputs, the instruction always incurs the same `l1GasCost`, `l2GasCost`, and `daGasCost`.
- The [`SET`](./instruction-set/#isa-section-set) instruction operates on a different sized constant (based on its `dst-type`). Therefore, this instruction's gas cost increases with the size of its input.
- The [`SET`](./instruction-set/#isa-section-set) instruction operates on a different sized constant (based on its `dstTag`). Therefore, this instruction's gas cost increases with the size of its input.
- Instructions that operate on a data range of a specified "size" scale in cost with that size. An example of this is the [`CALLDATACOPY`](./instruction-set/#isa-section-calldatacopy) argument which copies `copySize` words from `environment.calldata` to `machineState.memory`.
- The [`CALL`](./instruction-set/#isa-section-call)/[`STATICCALL`](./instruction-set/#isa-section-call)/`DELEGATECALL` instruction's gas cost is determined by its `*Gas` arguments, but any gas unused by the nested contract call's execution is refunded after its completion ([more on this later](#updating-the-calling-context-after-nested-call-halts)).
- An instruction with "offset" arguments (like [`ADD`](./instruction-set/#isa-section-add) and many others), has increased cost for each offset argument that is flagged as "indirect".
Expand All @@ -226,11 +225,11 @@ An instruction's gas cost is meant to reflect the computational cost of generati
> An instruction's gas cost takes into account the costs of associated downstream computations. An instruction that triggers accesses to the public data tree (`SLOAD`/`SSTORE`) incurs a cost that accounts for state access validation in later circuits (public kernel or rollup). A contract call instruction (`CALL`/`STATICCALL`/`DELEGATECALL`) incurs a cost accounting for the nested call's complete execution as well as any work required by the public kernel circuit for this additional call.
## Halting
### Halting

A context's execution can end with a **normal halt** or **exceptional halt**. A halt ends execution within the current context and returns control flow to the calling context.

### Normal halting
#### Normal halting

A normal halt occurs when the VM encounters an explicit halting instruction ([`RETURN`](./instruction-set#isa-section-return) or [`REVERT`](./instruction-set#isa-section-revert)). Such instructions consume gas normally and optionally initialize some output data before finally halting the current context's execution.

Expand All @@ -246,7 +245,7 @@ results.output = machineState.memory[instr.args.retOffset:instr.args.retOffset+i
> `results.output` is only relevant when the caller is a contract call itself. In other words, it is only relevant for [nested contract calls](#nested-contract-calls). When an [initial contract call](#initial-contract-calls) (initiated by a public execution request) halts normally, its `results.output` is ignored.
### Exceptional halting
#### Exceptional halting

An exceptional halt is not explicitly triggered by an instruction but instead occurs when an exceptional condition is met.

Expand Down Expand Up @@ -352,7 +351,7 @@ context = AvmContext {
worldState = <latest world state>,
journal = INITIAL_JOURNAL,
accruedSubstate = INITIAL_ACCRUED_SUBSTATE,
results = INITIAL_MESSAGE_CALL_RESULTS,
results = INITIAL_CONTRACT_CALL_RESULTS,
}
```

Expand All @@ -365,14 +364,13 @@ INITIAL_EXECUTION_ENVIRONMENT = ExecutionEnvironment {
address = PublicCallRequest.contractAddress,
storageAddress = PublicCallRequest.CallContext.storageContractAddress,
origin = TxRequest.origin,
l1GasPrice = TxRequest.l1GasPrice,
l2GasPrice = TxRequest.l2GasPrice,
daGasPrice = TxRequest.daGasPrice,
sender = PublicCallRequest.CallContext.msgSender,
portal = PublicCallRequest.CallContext.portalContractAddress,
blockHeader = <latest block header>,
globalVariables = <latest global variable values>
feePerL1Gas = TxRequest.feePerL1Gas,
feePerL2Gas = TxRequest.feePerL2Gas,
feePerDaGas = TxRequest.feePerDaGas,
contractCallDepth = 0,
globals = <latest global variable values>
isStaticCall = PublicCallRequest.CallContext.isStaticCall,
isDelegateCall = PublicCallRequest.CallContext.isDelegateCall,
calldata = PublicCallRequest.args,
Expand All @@ -385,7 +383,7 @@ INITIAL_MACHINE_STATE = MachineState {
daGasLeft = TxRequest.daGasLimit,
pc = 0,
internalCallStack = [], // initialized as empty
memory = [0, ..., 0], // all 32768 (2^32) entries are initialized to zero
memory = [0, ..., 0], // all 2^32 entries are initialized to zero
}
INITIAL_JOURNAL = Journal {
Expand All @@ -402,7 +400,7 @@ INITIAL_ACCRUED_SUBSTATE = AccruedSubstate {
unencryptedLogs = [], // initialized as empty
}
INITIAL_MESSAGE_CALL_RESULTS = ContractCallResults {
INITIAL_CONTRACT_CALL_RESULTS = ContractCallResults {
reverted = false,
output = [], // initialized as empty
}
Expand All @@ -423,7 +421,7 @@ nestedContext = AvmContext {
worldState: callingContext.worldState,
journal: callingContext.journal,
accruedSubstate: INITIAL_ACCRUED_SUBSTATE,
results: INITIAL_MESSAGE_CALL_RESULTS,
results: INITIAL_CONTRACT_CALL_RESULTS,
}
```

Expand All @@ -442,17 +440,16 @@ calldataStart = instr.args.argsOffset
calldataEnd = calldataStart + instr.args.argsSize
nestedExecutionEnvironment = ExecutionEnvironment {
address: instr.args.addr,
storageAddress: isDelegateCall ? callingContext.environment.storageAddress : instr.args.addr,
origin: callingContext.origin,
l1GasPrice: callingContext.l1GasPrice,
l2GasPrice: callingContext.l2GasPrice,
daGasPrice: callingContext.daGasPrice,
sender: callingContext.address,
address: instr.args.addr,
storageAddress: isDelegateCall ? callingContext.environment.storageAddress : instr.args.addr,
portal: contract.portal,
blockHeader: callingContext.blockHeader,
globalVariables: callingContext.globalVariables,
feePerL1Gas: callingContext.feePerL1Gas,
feePerL2Gas: callingContext.feePerL2Gas,
feePerDaGas: callingContext.feePerDaGas,
contractCallDepth: callingContext.contractCallDepth + 1,
globals: callingContext.globals,
isStaticCall: isStaticCall,
isDelegateCall: isDelegateCall,
calldata: callingContext.memory[calldataStart:calldataEnd],
Expand All @@ -465,7 +462,7 @@ nestedMachineState = MachineState {
daGasLeft: callingContext.machineState.memory[instr.args.gasOffset+2],
pc = 0,
internalCallStack = [], // initialized as empty
memory = [0, ..., 0], // all 32768 (2^32) entries are initialized to zero
memory = [0, ..., 0], // all 2^32 entries are initialized to zero
}
```
> The nested context's machine state's `*GasLeft` is initialized based on the call instruction's `gasOffset` argument. The caller allocates some amount of L1, L2, and DA gas to the nested call. It does so using the instruction's `gasOffset` argument. In particular, prior to the contract call instruction, the caller populates `M[gasOffset]` with the nested context's initial `l1GasLeft`. Likewise it populates `M[gasOffset+1]` with `l2GasLeft` and `M[gasOffset+2]` with `daGasLeft`.
Expand Down
Loading

0 comments on commit 52162ee

Please sign in to comment.