diff --git a/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts b/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts index c277c055628..2a7fa5a1758 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts @@ -1,48 +1,38 @@ /** - * 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, @@ -50,28 +40,45 @@ export enum Opcodes { 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, } diff --git a/yellow-paper/docs/public-vm/avm.md b/yellow-paper/docs/public-vm/avm.md index 2f06f409f1e..b3417afcb29 100644 --- a/yellow-paper/docs/public-vm/avm.md +++ b/yellow-paper/docs/public-vm/avm.md @@ -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 @@ -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; ], @@ -95,7 +94,7 @@ MachineState { daGasLeft: field, pc: field = 0, internalCallStack: Vector = [], // 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 } ``` @@ -121,7 +120,7 @@ WorldState { contracts: AztecAddress => {bytecode, portalAddress}, // read-only from within AVM blockHeaders: Vector, // 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; ]>, // append-only (no reads) from within AVM noteHashes: Vector, // append-only (no reads) from within AVM nullifiers: Vector, // append-only (no reads) from within AVM @@ -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". @@ -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. @@ -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. @@ -352,7 +351,7 @@ context = AvmContext { worldState = , journal = INITIAL_JOURNAL, accruedSubstate = INITIAL_ACCRUED_SUBSTATE, - results = INITIAL_MESSAGE_CALL_RESULTS, + results = INITIAL_CONTRACT_CALL_RESULTS, } ``` @@ -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 = , - globalVariables = + feePerL1Gas = TxRequest.feePerL1Gas, + feePerL2Gas = TxRequest.feePerL2Gas, + feePerDaGas = TxRequest.feePerDaGas, contractCallDepth = 0, + globals = isStaticCall = PublicCallRequest.CallContext.isStaticCall, isDelegateCall = PublicCallRequest.CallContext.isDelegateCall, calldata = PublicCallRequest.args, @@ -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 { @@ -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 } @@ -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, } ``` @@ -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], @@ -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`. diff --git a/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx b/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx index c362c88b840..4a28d65d2da 100644 --- a/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx +++ b/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx @@ -31,7 +31,7 @@ Click on an instruction name to jump to its section. 0x02 [`MUL`](#isa-section-mul) - Subtraction (a - b) + Multiplication (a * b) 128 { `M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k` @@ -122,1330 +122,1377 @@ Click on an instruction name to jump to its section. Type cast 96 { - `M[dstOffset] = cast(M[aOffset])` + `M[dstOffset] = cast(M[aOffset])` } - 0x0e [`SET`](#isa-section-set) - Set a memory word from a constant in the bytecode. - 64+N + 0x0e [`ADDRESS`](#isa-section-address) + Get the address of the currently executing l2 contract + 56 { - `M[dstOffset] = const` + `M[dstOffset] = context.environment.address` } - 0x0f [`MOV`](#isa-section-mov) - Move a word from source memory location to destination`. - 88 + 0x0f [`STORAGEADDRESS`](#isa-section-storageaddress) + Get the _storage_ address of the currently executing context + 56 { - `M[dstOffset] = M[srcOffset]` + `M[dstOffset] = context.environment.storageAddress` } - 0x10 [`CMOV`](#isa-section-cmov) - Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`). - 152 + 0x10 [`ORIGIN`](#isa-section-origin) + Get the transaction's origination address + 56 { - `M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]` + `M[dstOffset] = context.environment.origin` } - 0x11 [`CALLDATACOPY`](#isa-section-calldatacopy) - Copy calldata into memory. - 120 + 0x11 [`SENDER`](#isa-section-sender) + Get the address of the sender (caller of the current context) + 56 { - `M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize]` + `M[dstOffset] = context.environment.sender` } - 0x12 [`SLOAD`](#isa-section-sload) - Load a word from storage. - 88 + 0x12 [`PORTAL`](#isa-section-portal) + Get the address of the l1 portal contract + 56 { - `M[dstOffset] = storage[M[slotOffset]]` + `M[dstOffset] = context.environment.portal` } - 0x13 [`SSTORE`](#isa-section-sstore) - Write a word to storage. - 88 + 0x13 [`FEEPERL1GAS`](#isa-section-feeperl1gas) + Get the fee to be paid per "L1 gas" - constant for entire transaction + 56 { - `storage[M[slotOffset]] = M[srcOffset]` + `M[dstOffset] = context.environment.feePerL1Gas` } - 0x14 [`EMITNOTEHASH`](#isa-section-emitnotehash) - Emit a new note hash to be inserted into the notes tree + 0x14 [`FEEPERL2GAS`](#isa-section-feeperl2gas) + Get the fee to be paid per "L2 gas" - constant for entire transaction 56 - emitNoteHash(M[contentOffset]) + { + `M[dstOffset] = context.environment.feePerL2Gas` + } - 0x15 [`EMITNULLIFIER`](#isa-section-emitnullifier) - Emit a new nullifier to be inserted into the nullifier tree + 0x15 [`FEEPERDAGAS`](#isa-section-feeperdagas) + Get the fee to be paid per "DA gas" - constant for entire transaction 56 - emitNullifier(M[nullifierOffset]) + { + `M[dstOffset] = context.environment.feePerDaGas` + } - 0x16 [`SENDL2TOL1MSG`](#isa-section-sendl2tol1msg) - Send an L2-to-L1 message + 0x16 [`CONTRACTCALLDEPTH`](#isa-section-contractcalldepth) + Get how many contract calls deep the current call context is 56 - sendL2ToL1Message(M[contentOffset]) - - - 0x17 [`JUMP`](#isa-section-jump) - Jump to a location in the bytecode. - 48 { - `PC = loc` + `M[dstOffset] = context.environment.contractCallDepth` } - 0x18 [`JUMPI`](#isa-section-jumpi) - Conditionally jump to a location in the bytecode. - 88 + 0x17 [`CHAINID`](#isa-section-chainid) + Get this rollup's L1 chain ID + 56 { - `PC = M[condOffset] > 0 ? loc : PC` + `M[dstOffset] = context.environment.globals.chainId` } - 0x19 [`RETURN`](#isa-section-return) - Halt execution with `success`, optionally returning some data. - 88 + 0x18 [`VERSION`](#isa-section-version) + Get this rollup's L2 version ID + 56 { - `return(M[retOffset:retOffset+retSize])` + `M[dstOffset] = context.environment.globals.version` } - 0x1a [`REVERT`](#isa-section-revert) - Halt execution with `failure`, reverting state changes and optionally returning some data. - 88 + 0x19 [`BLOCKNUMBER`](#isa-section-blocknumber) + Get this L2 block's number + 56 { - `revert(M[retOffset:retOffset+retSize])` + `M[dstOffset] = context.environment.globals.blocknumber` } - 0x1b [`CALL`](#isa-section-call) - Call into another contract. - 248 - -{`M[successOffset] = call( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize])`} - - - - 0x1c [`STATICCALL`](#isa-section-staticcall) - Call into another contract, disallowing persistent state modifications. - 248 - -{`M[successOffset] = staticcall( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize])`} - + 0x1a [`TIMESTAMP`](#isa-section-timestamp) + Get this L2 block's timestamp + 56 + { + `M[dstOffset] = context.environment.globals.timestamp` + } - 0x1d [`ULOG`](#isa-section-ulog) - Emit an unencrypted log with data from the `field` memory page - 88 + 0x1b [`COINBASE`](#isa-section-coinbase) + Get the block's beneficiary address + 56 { - `ulog(M[logOffset:logOffset+logSize])` + `M[dstOffset] = context.environment.globals.coinbase` } - 0x1e [`CHAINID`](#isa-section-chainid) - Get this rollup's L1 chain ID + 0x1c [`BLOCKL1GASLIMIT`](#isa-section-blockl1gaslimit) + Total amount of "L1 gas" that a block can consume 56 { - `M[dstOffset] = Globals.chainId` + `M[dstOffset] = context.environment.globals.l1GasLimit` } - 0x1f [`VERSION`](#isa-section-version) - Get this rollup's L2 version ID + 0x1d [`BLOCKL2GASLIMIT`](#isa-section-blockl2gaslimit) + Total amount of "L2 gas" that a block can consume 56 { - `M[dstOffset] = Globals.version` + `M[dstOffset] = context.environment.globals.l2GasLimit` } - 0x20 [`BLOCKNUMBER`](#isa-section-blocknumber) - Get this block's number + 0x1e [`BLOCKDAGASLIMIT`](#isa-section-blockdagaslimit) + Total amount of "DA gas" that a block can consume 56 { - `M[dstOffset] = Globals.blocknumber` + `M[dstOffset] = context.environment.globals.daGasLimit` } - 0x21 [`TIMESTAMP`](#isa-section-timestamp) - Get this L2 block's timestamp - 56 + 0x1f [`CALLDATACOPY`](#isa-section-calldatacopy) + Copy calldata into memory + 120 { - `M[dstOffset] = Globals.timestamp` + `M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]` } - 0x22 [`COINBASE`](#isa-section-coinbase) - Get the block's beneficiary address + 0x20 [`L1GASLEFT`](#isa-section-l1gasleft) + Remaining "L1 gas" for this call (after this instruction) 56 { - `M[dstOffset] = Globals.coinbase` + `M[dstOffset] = context.machineState.l1GasLeft` } - 0x23 [`BLOCKL1GASLIMIT`](#isa-section-blockl1gaslimit) - Total amount of "L1 gas" that a block can consume + 0x21 [`L2GASLEFT`](#isa-section-l2gasleft) + Remaining "L2 gas" for this call (after this instruction) 56 { - `M[dstOffset] = Globals.l1GasLimit` + `M[dstOffset] = context.MachineState.l2GasLeft` } - 0x24 [`BLOCKL2GASLIMIT`](#isa-section-blockl2gaslimit) - Total amount of "L2 gas" that a block can consume + 0x22 [`DAGASLEFT`](#isa-section-dagasleft) + Remaining "DA gas" for this call (after this instruction) 56 { - `M[dstOffset] = Globals.l2GasLimit` + `M[dstOffset] = context.machineState.daGasLeft` } - 0x25 [`NOTESROOT`](#isa-section-notesroot) - Get the historical note-hash tree root as of the specified block number. - 88 + 0x23 [`JUMP`](#isa-section-jump) + Jump to a location in the bytecode + 48 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].note_hash_tree_root` + `context.machineState.pc = loc` } - 0x26 [`NULLIFIERSROOT`](#isa-section-nullroot) - Get the historical nullifier tree root as of the specified block number. + 0x24 [`JUMPI`](#isa-section-jumpi) + Conditionally jump to a location in the bytecode 88 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].nullifier_tree_root` + `context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc` } - 0x27 [`CONTRACTSROOT`](#isa-section-contractsroot) - Get the historical contracts tree root as of the specified block number. - 88 + 0x25 [`INTERNALCALL`](#isa-section-internalcall) + Make an internal call. Push the current PC to the internal call stack and jump to the target location. + 48 + +{`context.machineState.internalCallStack.push(context.machineState.pc) +context.machineState.pc = loc`} + + + + 0x26 [`INTERNALRETURN`](#isa-section-internalreturn) + Return from an internal call. Pop from the internal call stack and jump to the popped location. + 16 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].contracts_tree_root` + `context.machineState.pc = context.machineState.internalCallStack.pop()` } - 0x28 [`MSGSROOT`](#isa-section-msgsroot) - Get the historical l1-to-l2 message tree root as of the specified block number. - 88 + 0x27 [`SET`](#isa-section-set) + Set a memory word from a constant in the bytecode + 64+N { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].l1_to_l2_message_tree_root` + `M[dstOffset] = const` } - 0x29 [`PUBLICDATAROOT`](#isa-section-publicdataroot) - Get the historical public data tree root as of the specified block number. + 0x28 [`MOV`](#isa-section-mov) + Move a word from source memory location to destination 88 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].public_data_tree_root` + `M[dstOffset] = M[srcOffset]` } - 0x2a [`GLOBALSHASH`](#isa-section-globalshash) - Get the historical global variables hash as of the specified block number. - 88 + 0x29 [`CMOV`](#isa-section-cmov) + Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`) + 152 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].global_variables_hash` + `M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]` } - 0x2b [`BLOCKSROOT`](#isa-section-blocksroot) - Get the historical blocks tree root as of the specified block number. + 0x2a [`BLOCKHEADERBYNUM`](#isa-section-blockheaderbynum) + Get the block header as of the specified block number 88 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].archive_root` + `M[dstOffset:dstOffset+BLOCK_HEADER_LENGTH] = context.worldState.blockHeader[M[blockNumOffset]]` } - 0x2c [`GRANDROOT`](#isa-section-grandroot) - Get the historical grandfather tree root as of the specified block number. + 0x2b [`SLOAD`](#isa-section-sload) + Load a word from storage 88 { - `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].grandfather_tree_root` + `M[dstOffset] = context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]]` } - 0x2d [`ORIGIN`](#isa-section-origin) - Get the transaction's origination address - 56 + 0x2c [`SSTORE`](#isa-section-sstore) + Write a word to storage + 88 { - `M[dstOffset] = TxContext.origin` + `context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]] = M[srcOffset]` } - 0x2e [`REFUNDEE`](#isa-section-refundee) - The recipient of fee refunds for this transaction - 56 + 0x2d [`READL1TOL2MSG`](#isa-section-readl1tol2msg) + Reads an L1-to-L2 message + 120 { - `M[dstOffset] = TxContext.refundee` + `M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages(M[msgKeyOffset])` } - 0x2f [`FEEPERL1GAS`](#isa-section-feeperl1gas) - The fee to be paid per "L1 gas" - set by the transaction's original caller - 56 + 0x2e [`SENDL2TOL1MSG`](#isa-section-sendl2tol1msg) + Send an L2-to-L1 message + 88 { - `M[dstOffset] = TxContext.feePerL1Gas` + `context.worldState.l2ToL1Messages.append(M[msgOffset:msgOffset+msgSize])` } - 0x30 [`FEEPERL2GAS`](#isa-section-feeperl2gas) - The fee to be paid per "L2 gas" - set by the transaction's original caller + 0x2f [`EMITNOTEHASH`](#isa-section-emitnotehash) + Emit a new note hash to be inserted into the notes tree 56 { - `M[dstOffset] = TxContext.feePerL2Gas` + `context.worldState.newHashes.append(M[noteHashOffset])` } - 0x31 [`CALLER`](#isa-section-caller) - Get the address of the sender (the caller's context) + 0x30 [`EMITNULLIFIER`](#isa-section-emitnullifier) + Emit a new nullifier to be inserted into the nullifier tree 56 { - `M[dstOffset] = CallContext.sender` + `context.worldState.nullifiers.append(M[nullifierOffset])` } - 0x32 [`ADDRESS`](#isa-section-address) - Get the address of the currently executing l2 contract - 56 + 0x31 [`EMITUNENCRYPTEDLOG`](#isa-section-emitunencryptedlog) + Emit an unencrypted log + 88 { - `M[dstOffset] = CallContext.storageContractAddress` + `context.accruedSubstate.unencryptedLogs.append(M[logOffset:logOffset+logSize])` } - 0x33 [`PORTAL`](#isa-section-portal) - Get the address of the l1 portal contract - 56 - { - `M[dstOffset] = CallContext.portalAddress` - } + 0x32 [`CALL`](#isa-section-call) + Call into another contract + 248 + +{`M[successOffset] = call( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize])`} + - 0x34 [`CALLDEPTH`](#isa-section-calldepth) - Get how many calls deep the current call context is - 56 - { - `M[dstOffset] = CallContext.calldepth` - } + 0x33 [`STATICCALL`](#isa-section-staticcall) + Call into another contract, disallowing World State and Accrued Substate modifications + 248 + +{`M[successOffset] = staticcall( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize])`} + - 0x35 [`L1GAS`](#isa-section-l1gas) - Remaining "L1 gas" for this call (after this instruction). - 56 - { - `M[dstOffset] = LatestContext.l1Gas` - } + 0x34 [`RETURN`](#isa-section-return) + Halt execution within this context (without revert), optionally returning some data + 88 + +{`context.contractCallResults.output = M[retOffset:retOffset+retSize] +halt`} + - 0x36 [`L2GAS`](#isa-section-l2gas) - Remaining "L2 gas" for this call (after this instruction). - 56 - { - `M[dstOffset] = LatestContext.l2Gas` - } + 0x35 [`REVERT`](#isa-section-revert) + Halt execution within this context as `reverted`, optionally returning some data + 88 + +{`context.contractCallResults.output = M[retOffset:retOffset+retSize] +context.contractCallResults.reverted = true +halt`} + ## Instructions -### `ADD` (0x00) +### `ADD` Addition (a + b) [See in table.](#isa-table-add) -- **Category**: arithmetic +- **Opcode**: 0x00 +- **Category**: Compute - Arithmetic - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/ADD.png)](./images/bit-formats/ADD.png) -### `SUB` (0x01) +### `SUB` Subtraction (a - b) [See in table.](#isa-table-sub) -- **Category**: arithmetic +- **Opcode**: 0x01 +- **Category**: Compute - Arithmetic - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/SUB.png)](./images/bit-formats/SUB.png) -### `MUL` (0x02) -Subtraction (a - b) +### `MUL` +Multiplication (a * b) [See in table.](#isa-table-mul) -- **Category**: arithmetic +- **Opcode**: 0x02 +- **Category**: Compute - Arithmetic - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 +[![](./images/bit-formats/MUL.png)](./images/bit-formats/MUL.png) -### `DIV` (0x03) +### `DIV` Unsigned division (a / b) [See in table.](#isa-table-div) -- **Category**: arithmetic +- **Opcode**: 0x03 +- **Category**: Compute - Arithmetic - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] / M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/DIV.png)](./images/bit-formats/DIV.png) -### `EQ` (0x04) +### `EQ` Equality check (a == b) [See in table.](#isa-table-eq) -- **Category**: conditional +- **Opcode**: 0x04 +- **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/EQ.png)](./images/bit-formats/EQ.png) -### `LT` (0x05) +### `LT` Less-than check (a < b) [See in table.](#isa-table-lt) -- **Category**: conditional +- **Opcode**: 0x05 +- **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/LT.png)](./images/bit-formats/LT.png) -### `LTE` (0x06) +### `LTE` Less-than-or-equals check (a <= b) [See in table.](#isa-table-lte) -- **Category**: conditional +- **Opcode**: 0x06 +- **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/LTE.png)](./images/bit-formats/LTE.png) -### `AND` (0x07) +### `AND` Bitwise AND (a & b) [See in table.](#isa-table-and) -- **Category**: bitwise +- **Opcode**: 0x07 +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] AND M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/AND.png)](./images/bit-formats/AND.png) -### `OR` (0x08) +### `OR` Bitwise OR (a | b) [See in table.](#isa-table-or) -- **Category**: bitwise +- **Opcode**: 0x08 +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] OR M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/OR.png)](./images/bit-formats/OR.png) -### `XOR` (0x09) +### `XOR` Bitwise XOR (a ^ b) [See in table.](#isa-table-xor) -- **Category**: bitwise +- **Opcode**: 0x09 +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] XOR M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/XOR.png)](./images/bit-formats/XOR.png) -### `NOT` (0x0a) +### `NOT` Bitwise NOT (inversion) [See in table.](#isa-table-not) -- **Category**: bitwise +- **Opcode**: 0x0a +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = NOT M[aOffset]` -- **Tag checks**: `T[aOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 96 [![](./images/bit-formats/NOT.png)](./images/bit-formats/NOT.png) -### `SHL` (0x0b) +### `SHL` Bitwise leftward shift (a << b) [See in table.](#isa-table-shl) -- **Category**: bitwise +- **Opcode**: 0x0b +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] << M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/SHL.png)](./images/bit-formats/SHL.png) -### `SHR` (0x0c) +### `SHR` Bitwise rightward shift (a >> b) [See in table.](#isa-table-shr) -- **Category**: bitwise +- **Opcode**: 0x0c +- **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] >> M[bOffset]` -- **Tag checks**: `T[aOffset] == T[bOffset] == in-tag` -- **Tag updates**: `T[dstOffset] = in-tag` +- **Tag checks**: `T[aOffset] == T[bOffset] == inTag` +- **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/SHR.png)](./images/bit-formats/SHR.png) -### `CAST` (0x0d) +### `CAST` Type cast [See in table.](#isa-table-cast) -- **Category**: types +- **Opcode**: 0x0d +- **Category**: Type Conversions - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **dst-tag**: The [tag/size](./state-model#tags-and-tagged-memory) to tag the destination with but not to check inputs against. + - **dstTag**: The [tag/size](./state-model#tags-and-tagged-memory) to tag the destination with but not to check inputs against. - **Args**: - **aOffset**: memory offset of word to cast - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = cast(M[aOffset])` -- **Details**: Cast a word in memory based on the `dst-tag` specified in the bytecode. Truncates (`M[dstOffset] = M[aOffset] mod 2^dstsize`) when casting to a smaller type, left-zero-pads when casting to a larger type. See [here](./state-model#cast-and-tag-conversions) for more details. -- **Tag updates**: `T[dstOffset] = dst-tag` +- **Expression**: `M[dstOffset] = cast(M[aOffset])` +- **Details**: Cast a word in memory based on the `dstTag` specified in the bytecode. Truncates (`M[dstOffset] = M[aOffset] mod 2^dstsize`) when casting to a smaller type, left-zero-pads when casting to a larger type. See [here](./state-model#cast-and-tag-conversions) for more details. +- **Tag updates**: `T[dstOffset] = dstTag` - **Bit-size**: 96 [![](./images/bit-formats/CAST.png)](./images/bit-formats/CAST.png) -### `SET` (0x0e) -Set a memory word from a constant in the bytecode. +### `ADDRESS` +Get the address of the currently executing l2 contract -[See in table.](#isa-table-set) +[See in table.](#isa-table-address) -- **Category**: memory +- **Opcode**: 0x0e +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **in-tag**: The [type/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for SET. - **Args**: - - **const**: an N-bit constant value from the bytecode to store in memory (any type except `field`) - - **dstOffset**: memory offset specifying where to store the constant -- **Expression**: `M[dstOffset] = const` -- **Details**: Set memory word at `dstOffset` to `const`'s immediate value. `const`'s bit-size (N) can be 8, 16, 32, 64, or 128 based on `in-tag`. It _cannot be 254 (`field` type)_! -- **Tag updates**: `T[dstOffset] = in-tag` -- **Bit-size**: 64+N + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.address` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/SET.png)](./images/bit-formats/SET.png) +[![](./images/bit-formats/ADDRESS.png)](./images/bit-formats/ADDRESS.png) -### `MOV` (0x0f) -Move a word from source memory location to destination`. +### `STORAGEADDRESS` +Get the _storage_ address of the currently executing context -[See in table.](#isa-table-mov) +[See in table.](#isa-table-storageaddress) -- **Category**: memory +- **Opcode**: 0x0f +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **srcOffset**: memory offset of word to move - - **dstOffset**: memory offset specifying where to store that word -- **Expression**: `M[dstOffset] = M[srcOffset]` -- **Tag updates**: `T[dstOffset] = T[srcOffset]` -- **Bit-size**: 88 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.storageAddress` +- **Details**: The storage address is used for public storage accesses. +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/MOV.png)](./images/bit-formats/MOV.png) +[![](./images/bit-formats/STORAGEADDRESS.png)](./images/bit-formats/STORAGEADDRESS.png) -### `CMOV` (0x10) -Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`). +### `ORIGIN` +Get the transaction's origination address -[See in table.](#isa-table-cmov) +[See in table.](#isa-table-origin) -- **Category**: memory +- **Opcode**: 0x10 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **aOffset**: memory offset of word 'a' to conditionally move - - **bOffset**: memory offset of word 'b' to conditionally move - - **condOffset**: memory offset of the operations 'conditional' input - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]` -- **Details**: One of two source memory locations is chosen based on the condition. `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type. -- **Tag updates**: `T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]` -- **Bit-size**: 152 +- **Expression**: `M[dstOffset] = context.environment.origin` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/CMOV.png)](./images/bit-formats/CMOV.png) +[![](./images/bit-formats/ORIGIN.png)](./images/bit-formats/ORIGIN.png) -### `CALLDATACOPY` (0x11) -Copy calldata into memory. +### `SENDER` +Get the address of the sender (caller of the current context) -[See in table.](#isa-table-calldatacopy) +[See in table.](#isa-table-sender) -- **Category**: contract calls +- **Opcode**: 0x11 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **cdOffset**: offset into calldata to copy from - - **copySize**: number of words to copy - - **dstOffset**: memory offset specifying where to copy the first word to -- **Expression**: `M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize]` -- **Details**: Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally. -- **Tag updates**: `T[dstOffset:dstOffset+copySize] = field` -- **Bit-size**: 120 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.sender` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/CALLDATACOPY.png)](./images/bit-formats/CALLDATACOPY.png) +[![](./images/bit-formats/SENDER.png)](./images/bit-formats/SENDER.png) -### `SLOAD` (0x12) -Load a word from storage. +### `PORTAL` +Get the address of the l1 portal contract -[See in table.](#isa-table-sload) +[See in table.](#isa-table-portal) -- **Category**: storage & messaging +- **Opcode**: 0x12 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **slotOffset**: memory offset of the storage slot to load from - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = storage[M[slotOffset]]` -- **Details**: Load a word from this contract's persistent public storage into memory. -- **Tag updates**: `T[dstOffset] = field` -- **Bit-size**: 88 +- **Expression**: `M[dstOffset] = context.environment.portal` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/SLOAD.png)](./images/bit-formats/SLOAD.png) +[![](./images/bit-formats/PORTAL.png)](./images/bit-formats/PORTAL.png) -### `SSTORE` (0x13) -Write a word to storage. +### `FEEPERL1GAS` +Get the fee to be paid per "L1 gas" - constant for entire transaction -[See in table.](#isa-table-sstore) +[See in table.](#isa-table-feeperl1gas) -- **Category**: storage & messaging +- **Opcode**: 0x13 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **srcOffset**: memory offset of the word to store - - **slotOffset**: memory offset containing the storage slot to store to -- **Expression**: `storage[M[slotOffset]] = M[srcOffset]` -- **Details**: Store a word from memory into this contract's persistent public storage. -- **Bit-size**: 88 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.feePerL1Gas` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/SSTORE.png)](./images/bit-formats/SSTORE.png) +[![](./images/bit-formats/FEEPERL1GAS.png)](./images/bit-formats/FEEPERL1GAS.png) -### `EMITNOTEHASH` (0x14) -Emit a new note hash to be inserted into the notes tree +### `FEEPERL2GAS` +Get the fee to be paid per "L2 gas" - constant for entire transaction -[See in table.](#isa-table-emitnotehash) +[See in table.](#isa-table-feeperl2gas) -- **Category**: storage & messaging +- **Opcode**: 0x14 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **noteHashOffset**: memory offset of the note hash -- **Expression**: emitNoteHash(M[contentOffset]) + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.feePerL2Gas` +- **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/EMITNOTEHASH.png)](./images/bit-formats/EMITNOTEHASH.png) +[![](./images/bit-formats/FEEPERL2GAS.png)](./images/bit-formats/FEEPERL2GAS.png) -### `EMITNULLIFIER` (0x15) -Emit a new nullifier to be inserted into the nullifier tree +### `FEEPERDAGAS` +Get the fee to be paid per "DA gas" - constant for entire transaction -[See in table.](#isa-table-emitnullifier) +[See in table.](#isa-table-feeperdagas) -- **Category**: storage & messaging +- **Opcode**: 0x15 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **nullifierOffset**: memory offset of nullifier -- **Expression**: emitNullifier(M[nullifierOffset]) + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.feePerDaGas` +- **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/EMITNULLIFIER.png)](./images/bit-formats/EMITNULLIFIER.png) +[![](./images/bit-formats/FEEPERDAGAS.png)](./images/bit-formats/FEEPERDAGAS.png) -### `SENDL2TOL1MSG` (0x16) -Send an L2-to-L1 message +### `CONTRACTCALLDEPTH` +Get how many contract calls deep the current call context is -[See in table.](#isa-table-sendl2tol1msg) +[See in table.](#isa-table-contractcalldepth) -- **Category**: storage & messaging +- **Opcode**: 0x16 +- **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **contentOffset**: memory offset of the message content -- **Expression**: sendL2ToL1Message(M[contentOffset]) + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.contractCallDepth` +- **Details**: Note: security issues with EVM's tx.origin can be resolved by asserting `calldepth == 0`. +- **Tag updates**: `T[dstOffset] = u8` - **Bit-size**: 56 -[![](./images/bit-formats/SENDL2TOL1MSG.png)](./images/bit-formats/SENDL2TOL1MSG.png) +[![](./images/bit-formats/CONTRACTCALLDEPTH.png)](./images/bit-formats/CONTRACTCALLDEPTH.png) -### `JUMP` (0x17) -Jump to a location in the bytecode. +### `CHAINID` +Get this rollup's L1 chain ID -[See in table.](#isa-table-jump) +[See in table.](#isa-table-chainid) -- **Category**: control +- **Opcode**: 0x17 +- **Category**: Execution Environment - Globals +- **Flags**: + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **loc**: target location to jump to -- **Expression**: `PC = loc` -- **Details**: Target location is an immediate value (a constant in the bytecode). -- **Bit-size**: 48 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.globals.chainId` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/JUMP.png)](./images/bit-formats/JUMP.png) +[![](./images/bit-formats/CHAINID.png)](./images/bit-formats/CHAINID.png) -### `JUMPI` (0x18) -Conditionally jump to a location in the bytecode. +### `VERSION` +Get this rollup's L2 version ID -[See in table.](#isa-table-jumpi) +[See in table.](#isa-table-version) -- **Category**: control +- **Opcode**: 0x18 +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **loc**: target location conditionally jump to - - **condOffset**: memory offset of the operations 'conditional' input -- **Expression**: `PC = M[condOffset] > 0 ? loc : PC` -- **Details**: Target location is an immediate value (a constant in the bytecode). `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type. -- **Bit-size**: 88 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.globals.version` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/JUMPI.png)](./images/bit-formats/JUMPI.png) +[![](./images/bit-formats/VERSION.png)](./images/bit-formats/VERSION.png) -### `RETURN` (0x19) -Halt execution with `success`, optionally returning some data. +### `BLOCKNUMBER` +Get this L2 block's number -[See in table.](#isa-table-return) +[See in table.](#isa-table-blocknumber) -- **Category**: contract calls +- **Opcode**: 0x19 +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **retOffset**: memory offset of first word to return - - **retSize**: number of words to return -- **Expression**: `return(M[retOffset:retOffset+retSize])` -- **Details**: Return control flow to the calling context/contract. -- **Bit-size**: 88 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.globals.blocknumber` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/RETURN.png)](./images/bit-formats/RETURN.png) +[![](./images/bit-formats/BLOCKNUMBER.png)](./images/bit-formats/BLOCKNUMBER.png) -### `REVERT` (0x1a) -Halt execution with `failure`, reverting state changes and optionally returning some data. +### `TIMESTAMP` +Get this L2 block's timestamp -[See in table.](#isa-table-revert) +[See in table.](#isa-table-timestamp) -- **Category**: contract calls +- **Opcode**: 0x1a +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **retOffset**: memory offset of first word to return - - **retSize**: number of words to return -- **Expression**: `revert(M[retOffset:retOffset+retSize])` -- **Details**: Return control flow to the calling context/contract. -- **Bit-size**: 88 - -[![](./images/bit-formats/REVERT.png)](./images/bit-formats/REVERT.png) - -### `CALL` (0x1b) -Call into another contract. - -[See in table.](#isa-table-call) - -- **Category**: contract calls -- **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. -- **Args**: - - **gasOffset**: offset to two words containing `{l1Gas, l2Gas}`: amount of L1 and L2 gas to provide to the callee - - **addrOffset**: address of the contract to call - - **argsOffset**: memory offset to args (will become the callee's calldata) - - **argsSize**: number of words to pass via callee's calldata - - **retOffset**: destination memory offset specifying where to store the data returned from the callee - - **retSize**: number of words to copy from data returned by callee - - **successOffset**: destination memory offset specifying where to store the call's success (0: failure, 1: success) -- **Expression**: - -{`M[successOffset] = call( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize])`} - -- **Details**: Creates a new CallContext, triggers execution of the corresponding contract code, - and then resumes execution in the current CallContext. A non-existent contract or one - with no code will return success. Nested call has an incremented `CallContext.calldepth`. -- **Tag checks**: `T[gasOffset] == T[gasOffset+1] == u32` -- **Tag updates**: - -{`T[successOffset] = u8 -T[retOffset:retOffset+retSize] = field`} - -- **Bit-size**: 248 - -[![](./images/bit-formats/CALL.png)](./images/bit-formats/CALL.png) - -### `STATICCALL` (0x1c) -Call into another contract, disallowing persistent state modifications. - -[See in table.](#isa-table-staticcall) - -- **Category**: contract calls -- **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. -- **Args**: - - **gasOffset**: offset to two words containing `{l1Gas, l2Gas}`: amount of L1 and L2 gas to provide to the callee - - **addrOffset**: address of the contract to call - - **argsOffset**: memory offset to args (will become the callee's calldata) - - **argsSize**: number of words to pass via callee's calldata - - **retOffset**: destination memory offset specifying where to store the data returned from the callee - - **retSize**: number of words to copy from data returned by callee - - **successOffset**: destination memory offset specifying where to store the call's success (0: failure, 1: success) -- **Expression**: - -{`M[successOffset] = staticcall( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize])`} - -- **Details**: Same as `CALL`, but the callee is cannot modify persistent state. Disallowed instructions are `SSTORE`, `ULOG`, `CALL`. -- **Tag checks**: `T[gasOffset] == T[gasOffset+1] == u32` -- **Tag updates**: - -{`T[successOffset] = u8 -T[retOffset:retOffset+retSize] = field`} - -- **Bit-size**: 248 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.globals.timestamp` +- **Tag updates**: `T[dstOffset] = u64` +- **Bit-size**: 56 -[![](./images/bit-formats/STATICCALL.png)](./images/bit-formats/STATICCALL.png) +[![](./images/bit-formats/TIMESTAMP.png)](./images/bit-formats/TIMESTAMP.png) -### `ULOG` (0x1d) -Emit an unencrypted log with data from the `field` memory page +### `COINBASE` +Get the block's beneficiary address -[See in table.](#isa-table-ulog) +[See in table.](#isa-table-coinbase) -- **Category**: logging +- **Opcode**: 0x1b +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **logOffset**: memory offset of the data to log - - **logSize**: number of words to log -- **Expression**: `ulog(M[logOffset:logOffset+logSize])` -- **Bit-size**: 88 + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = context.environment.globals.coinbase` +- **Tag updates**: `T[dstOffset] = u32` +- **Bit-size**: 56 -[![](./images/bit-formats/ULOG.png)](./images/bit-formats/ULOG.png) +[![](./images/bit-formats/COINBASE.png)](./images/bit-formats/COINBASE.png) -### `CHAINID` (0x1e) -Get this rollup's L1 chain ID +### `BLOCKL1GASLIMIT` +Total amount of "L1 gas" that a block can consume -[See in table.](#isa-table-chainid) +[See in table.](#isa-table-blockl1gaslimit) -- **Category**: block info +- **Opcode**: 0x1c +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.chainId` +- **Expression**: `M[dstOffset] = context.environment.globals.l1GasLimit` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/CHAINID.png)](./images/bit-formats/CHAINID.png) +[![](./images/bit-formats/BLOCKL1GASLIMIT.png)](./images/bit-formats/BLOCKL1GASLIMIT.png) -### `VERSION` (0x1f) -Get this rollup's L2 version ID +### `BLOCKL2GASLIMIT` +Total amount of "L2 gas" that a block can consume -[See in table.](#isa-table-version) +[See in table.](#isa-table-blockl2gaslimit) -- **Category**: block info +- **Opcode**: 0x1d +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.version` +- **Expression**: `M[dstOffset] = context.environment.globals.l2GasLimit` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/VERSION.png)](./images/bit-formats/VERSION.png) +[![](./images/bit-formats/BLOCKL2GASLIMIT.png)](./images/bit-formats/BLOCKL2GASLIMIT.png) -### `BLOCKNUMBER` (0x20) -Get this block's number +### `BLOCKDAGASLIMIT` +Total amount of "DA gas" that a block can consume -[See in table.](#isa-table-blocknumber) +[See in table.](#isa-table-blockdagaslimit) -- **Category**: block info +- **Opcode**: 0x1e +- **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.blocknumber` +- **Expression**: `M[dstOffset] = context.environment.globals.daGasLimit` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/BLOCKNUMBER.png)](./images/bit-formats/BLOCKNUMBER.png) +[![](./images/bit-formats/BLOCKDAGASLIMIT.png)](./images/bit-formats/BLOCKDAGASLIMIT.png) -### `TIMESTAMP` (0x21) -Get this L2 block's timestamp +### `CALLDATACOPY` +Copy calldata into memory -[See in table.](#isa-table-timestamp) +[See in table.](#isa-table-calldatacopy) -- **Category**: block info +- **Opcode**: 0x1f +- **Category**: Execution Environment - Calldata - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.timestamp` -- **Tag updates**: `T[dstOffset] = u64` -- **Bit-size**: 56 + - **cdOffset**: offset into calldata to copy from + - **copySize**: number of words to copy + - **dstOffset**: memory offset specifying where to copy the first word to +- **Expression**: `M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]` +- **Details**: Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally. +- **Tag updates**: `T[dstOffset:dstOffset+copySize] = field` +- **Bit-size**: 120 -[![](./images/bit-formats/TIMESTAMP.png)](./images/bit-formats/TIMESTAMP.png) +[![](./images/bit-formats/CALLDATACOPY.png)](./images/bit-formats/CALLDATACOPY.png) -### `COINBASE` (0x22) -Get the block's beneficiary address +### `L1GASLEFT` +Remaining "L1 gas" for this call (after this instruction) -[See in table.](#isa-table-coinbase) +[See in table.](#isa-table-l1gasleft) -- **Category**: block info +- **Opcode**: 0x20 +- **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.coinbase` +- **Expression**: `M[dstOffset] = context.machineState.l1GasLeft` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/COINBASE.png)](./images/bit-formats/COINBASE.png) +[![](./images/bit-formats/L1GASLEFT.png)](./images/bit-formats/L1GASLEFT.png) -### `BLOCKL1GASLIMIT` (0x23) -Total amount of "L1 gas" that a block can consume +### `L2GASLEFT` +Remaining "L2 gas" for this call (after this instruction) -[See in table.](#isa-table-blockl1gaslimit) +[See in table.](#isa-table-l2gasleft) -- **Category**: block info +- **Opcode**: 0x21 +- **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.l1GasLimit` +- **Expression**: `M[dstOffset] = context.MachineState.l2GasLeft` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/BLOCKL1GASLIMIT.png)](./images/bit-formats/BLOCKL1GASLIMIT.png) +[![](./images/bit-formats/L2GASLEFT.png)](./images/bit-formats/L2GASLEFT.png) -### `BLOCKL2GASLIMIT` (0x24) -Total amount of "L2 gas" that a block can consume +### `DAGASLEFT` +Remaining "DA gas" for this call (after this instruction) -[See in table.](#isa-table-blockl2gaslimit) +[See in table.](#isa-table-dagasleft) -- **Category**: block info +- **Opcode**: 0x22 +- **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = Globals.l2GasLimit` +- **Expression**: `M[dstOffset] = context.machineState.daGasLeft` - **Tag updates**: `T[dstOffset] = u32` - **Bit-size**: 56 -[![](./images/bit-formats/BLOCKL2GASLIMIT.png)](./images/bit-formats/BLOCKL2GASLIMIT.png) +[![](./images/bit-formats/DAGASLEFT.png)](./images/bit-formats/DAGASLEFT.png) -### `NOTESROOT` (0x25) -Get the historical note-hash tree root as of the specified block number. +### `JUMP` +Jump to a location in the bytecode -[See in table.](#isa-table-notesroot) +[See in table.](#isa-table-jump) -- **Category**: historical access -- **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. +- **Opcode**: 0x23 +- **Category**: Machine State - Control Flow - **Args**: - - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].note_hash_tree_root` -- **Tag updates**: `T[dstOffset] = field` -- **Bit-size**: 88 + - **loc**: target location to jump to +- **Expression**: `context.machineState.pc = loc` +- **Details**: Target location is an immediate value (a constant in the bytecode). +- **Bit-size**: 48 -[![](./images/bit-formats/NOTESROOT.png)](./images/bit-formats/NOTESROOT.png) +[![](./images/bit-formats/JUMP.png)](./images/bit-formats/JUMP.png) -### `NULLIFIERSROOT` (0x26) -Get the historical nullifier tree root as of the specified block number. +### `JUMPI` +Conditionally jump to a location in the bytecode -[See in table.](#isa-table-nullroot) +[See in table.](#isa-table-jumpi) -- **Category**: historical access +- **Opcode**: 0x24 +- **Category**: Machine State - Control Flow - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].nullifier_tree_root` -- **Tag updates**: `T[dstOffset] = field` + - **loc**: target location conditionally jump to + - **condOffset**: memory offset of the operations 'conditional' input +- **Expression**: `context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc` +- **Details**: Target location is an immediate value (a constant in the bytecode). `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type. - **Bit-size**: 88 -[![](./images/bit-formats/NULLIFIERSROOT.png)](./images/bit-formats/NULLIFIERSROOT.png) +[![](./images/bit-formats/JUMPI.png)](./images/bit-formats/JUMPI.png) -### `CONTRACTSROOT` (0x27) -Get the historical contracts tree root as of the specified block number. +### `INTERNALCALL` +Make an internal call. Push the current PC to the internal call stack and jump to the target location. -[See in table.](#isa-table-contractsroot) +[See in table.](#isa-table-internalcall) -- **Category**: historical access -- **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. +- **Opcode**: 0x25 +- **Category**: Machine State - Control Flow - **Args**: - - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].contracts_tree_root` -- **Tag updates**: `T[dstOffset] = field` -- **Bit-size**: 88 + - **loc**: target location to jump/call to +- **Expression**: + +{`context.machineState.internalCallStack.push(context.machineState.pc) +context.machineState.pc = loc`} + +- **Details**: Target location is an immediate value (a constant in the bytecode). +- **Bit-size**: 48 + + +### `INTERNALRETURN` +Return from an internal call. Pop from the internal call stack and jump to the popped location. + +[See in table.](#isa-table-internalreturn) + +- **Opcode**: 0x26 +- **Category**: Machine State - Control Flow +- **Expression**: `context.machineState.pc = context.machineState.internalCallStack.pop()` +- **Bit-size**: 16 -[![](./images/bit-formats/CONTRACTSROOT.png)](./images/bit-formats/CONTRACTSROOT.png) +[![](./images/bit-formats/INTERNALRETURN.png)](./images/bit-formats/INTERNALRETURN.png) -### `MSGSROOT` (0x28) -Get the historical l1-to-l2 message tree root as of the specified block number. +### `SET` +Set a memory word from a constant in the bytecode -[See in table.](#isa-table-msgsroot) +[See in table.](#isa-table-set) -- **Category**: historical access +- **Opcode**: 0x27 +- **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [type/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for SET. - **Args**: - - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].l1_to_l2_message_tree_root` -- **Tag updates**: `T[dstOffset] = field` -- **Bit-size**: 88 + - **const**: an N-bit constant value from the bytecode to store in memory (any type except `field`) + - **dstOffset**: memory offset specifying where to store the constant +- **Expression**: `M[dstOffset] = const` +- **Details**: Set memory word at `dstOffset` to `const`'s immediate value. `const`'s bit-size (N) can be 8, 16, 32, 64, or 128 based on `inTag`. It _cannot be 254 (`field` type)_! +- **Tag updates**: `T[dstOffset] = inTag` +- **Bit-size**: 64+N -[![](./images/bit-formats/MSGSROOT.png)](./images/bit-formats/MSGSROOT.png) +[![](./images/bit-formats/SET.png)](./images/bit-formats/SET.png) -### `PUBLICDATAROOT` (0x29) -Get the historical public data tree root as of the specified block number. +### `MOV` +Move a word from source memory location to destination -[See in table.](#isa-table-publicdataroot) +[See in table.](#isa-table-mov) -- **Category**: historical access +- **Opcode**: 0x28 +- **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].public_data_tree_root` -- **Tag updates**: `T[dstOffset] = field` + - **srcOffset**: memory offset of word to move + - **dstOffset**: memory offset specifying where to store that word +- **Expression**: `M[dstOffset] = M[srcOffset]` +- **Tag updates**: `T[dstOffset] = T[srcOffset]` - **Bit-size**: 88 -[![](./images/bit-formats/PUBLICDATAROOT.png)](./images/bit-formats/PUBLICDATAROOT.png) +[![](./images/bit-formats/MOV.png)](./images/bit-formats/MOV.png) -### `GLOBALSHASH` (0x2a) -Get the historical global variables hash as of the specified block number. +### `CMOV` +Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`) -[See in table.](#isa-table-globalshash) +[See in table.](#isa-table-cmov) -- **Category**: historical access +- **Opcode**: 0x29 +- **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **blockNumOffset**: memory offset of the block number input + - **aOffset**: memory offset of word 'a' to conditionally move + - **bOffset**: memory offset of word 'b' to conditionally move + - **condOffset**: memory offset of the operations 'conditional' input - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].global_variables_hash` -- **Tag updates**: `T[dstOffset] = field` -- **Bit-size**: 88 +- **Expression**: `M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]` +- **Details**: One of two source memory locations is chosen based on the condition. `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type. +- **Tag updates**: `T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]` +- **Bit-size**: 152 -[![](./images/bit-formats/GLOBALSHASH.png)](./images/bit-formats/GLOBALSHASH.png) +[![](./images/bit-formats/CMOV.png)](./images/bit-formats/CMOV.png) -### `BLOCKSROOT` (0x2b) -Get the historical blocks tree root as of the specified block number. +### `BLOCKHEADERBYNUM` +Get the block header as of the specified block number -[See in table.](#isa-table-blocksroot) +[See in table.](#isa-table-blockheaderbynum) -- **Category**: historical access +- **Opcode**: 0x2a +- **Category**: World State - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **blockNumOffset**: memory offset of the block number input - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].archive_root` -- **Tag updates**: `T[dstOffset] = field` + - **dstOffset**: memory offset specifying where to store operation's result's 0th word +- **Expression**: `M[dstOffset:dstOffset+BLOCK_HEADER_LENGTH] = context.worldState.blockHeader[M[blockNumOffset]]` +- **Tag updates**: `T[dstOffset:dstOffset+BLOCK_HEADER_LENGTh] = field` - **Bit-size**: 88 -[![](./images/bit-formats/BLOCKSROOT.png)](./images/bit-formats/BLOCKSROOT.png) +[![](./images/bit-formats/BLOCKHEADERBYNUM.png)](./images/bit-formats/BLOCKHEADERBYNUM.png) -### `GRANDROOT` (0x2c) -Get the historical grandfather tree root as of the specified block number. +### `SLOAD` +Load a word from storage -[See in table.](#isa-table-grandroot) +[See in table.](#isa-table-sload) -- **Category**: historical access +- **Opcode**: 0x2b +- **Category**: World State - Public Storage - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **blockNumOffset**: memory offset of the block number input + - **slotOffset**: memory offset of the storage slot to load from - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].grandfather_tree_root` +- **Expression**: `M[dstOffset] = context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]]` +- **Details**: Load a word from this contract's persistent public storage into memory. - **Tag updates**: `T[dstOffset] = field` - **Bit-size**: 88 -[![](./images/bit-formats/GRANDROOT.png)](./images/bit-formats/GRANDROOT.png) +[![](./images/bit-formats/SLOAD.png)](./images/bit-formats/SLOAD.png) -### `ORIGIN` (0x2d) -Get the transaction's origination address +### `SSTORE` +Write a word to storage -[See in table.](#isa-table-origin) +[See in table.](#isa-table-sstore) -- **Category**: tx context +- **Opcode**: 0x2c +- **Category**: World State - Public Storage - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = TxContext.origin` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **srcOffset**: memory offset of the word to store + - **slotOffset**: memory offset containing the storage slot to store to +- **Expression**: `context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]] = M[srcOffset]` +- **Details**: Store a word from memory into this contract's persistent public storage. +- **Bit-size**: 88 -[![](./images/bit-formats/ORIGIN.png)](./images/bit-formats/ORIGIN.png) +[![](./images/bit-formats/SSTORE.png)](./images/bit-formats/SSTORE.png) -### `REFUNDEE` (0x2e) -The recipient of fee refunds for this transaction +### `READL1TOL2MSG` +Reads an L1-to-L2 message -[See in table.](#isa-table-refundee) +[See in table.](#isa-table-readl1tol2msg) -- **Category**: tx context +- **Opcode**: 0x2d +- **Category**: World State - Messaging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = TxContext.refundee` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **msgKeyOffset**: memory offset of the message's key + - **dstOffset**: memory offset to place the 0th word of the message content + - **msgSize**: number of words in the message +- **Expression**: `M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages(M[msgKeyOffset])` +- **Tag updates**: `T[dstOffset:dstOffset+msgSize] = field` +- **Bit-size**: 120 -[![](./images/bit-formats/REFUNDEE.png)](./images/bit-formats/REFUNDEE.png) +[![](./images/bit-formats/READL1TOL2MSG.png)](./images/bit-formats/READL1TOL2MSG.png) -### `FEEPERL1GAS` (0x2f) -The fee to be paid per "L1 gas" - set by the transaction's original caller +### `SENDL2TOL1MSG` +Send an L2-to-L1 message -[See in table.](#isa-table-feeperl1gas) +[See in table.](#isa-table-sendl2tol1msg) -- **Category**: tx context +- **Opcode**: 0x2e +- **Category**: World State - Messaging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = TxContext.feePerL1Gas` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **msgOffset**: memory offset of the message content + - **msgSize**: number of words in the message +- **Expression**: `context.worldState.l2ToL1Messages.append(M[msgOffset:msgOffset+msgSize])` +- **Bit-size**: 88 -[![](./images/bit-formats/FEEPERL1GAS.png)](./images/bit-formats/FEEPERL1GAS.png) +[![](./images/bit-formats/SENDL2TOL1MSG.png)](./images/bit-formats/SENDL2TOL1MSG.png) -### `FEEPERL2GAS` (0x30) -The fee to be paid per "L2 gas" - set by the transaction's original caller +### `EMITNOTEHASH` +Emit a new note hash to be inserted into the notes tree -[See in table.](#isa-table-feeperl2gas) +[See in table.](#isa-table-emitnotehash) -- **Category**: tx context +- **Opcode**: 0x2f +- **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = TxContext.feePerL2Gas` -- **Tag updates**: `T[dstOffset] = u32` + - **noteHashOffset**: memory offset of the note hash +- **Expression**: `context.worldState.newHashes.append(M[noteHashOffset])` - **Bit-size**: 56 -[![](./images/bit-formats/FEEPERL2GAS.png)](./images/bit-formats/FEEPERL2GAS.png) +[![](./images/bit-formats/EMITNOTEHASH.png)](./images/bit-formats/EMITNOTEHASH.png) -### `CALLER` (0x31) -Get the address of the sender (the caller's context) +### `EMITNULLIFIER` +Emit a new nullifier to be inserted into the nullifier tree -[See in table.](#isa-table-caller) +[See in table.](#isa-table-emitnullifier) -- **Category**: call context +- **Opcode**: 0x30 +- **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = CallContext.sender` -- **Tag updates**: `T[dstOffset] = u32` + - **nullifierOffset**: memory offset of nullifier +- **Expression**: `context.worldState.nullifiers.append(M[nullifierOffset])` - **Bit-size**: 56 -[![](./images/bit-formats/CALLER.png)](./images/bit-formats/CALLER.png) +[![](./images/bit-formats/EMITNULLIFIER.png)](./images/bit-formats/EMITNULLIFIER.png) -### `ADDRESS` (0x32) -Get the address of the currently executing l2 contract +### `EMITUNENCRYPTEDLOG` +Emit an unencrypted log -[See in table.](#isa-table-address) +[See in table.](#isa-table-emitunencryptedlog) -- **Category**: call context +- **Opcode**: 0x31 +- **Category**: Accrued Substate - Logging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = CallContext.storageContractAddress` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **logOffset**: memory offset of the data to log + - **logSize**: number of words to log +- **Expression**: `context.accruedSubstate.unencryptedLogs.append(M[logOffset:logOffset+logSize])` +- **Bit-size**: 88 -[![](./images/bit-formats/ADDRESS.png)](./images/bit-formats/ADDRESS.png) +[![](./images/bit-formats/EMITUNENCRYPTEDLOG.png)](./images/bit-formats/EMITUNENCRYPTEDLOG.png) -### `PORTAL` (0x33) -Get the address of the l1 portal contract +### `CALL` +Call into another contract -[See in table.](#isa-table-portal) +[See in table.](#isa-table-call) -- **Category**: call context +- **Opcode**: 0x32 +- **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = CallContext.portalAddress` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **gasOffset**: offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee + - **addrOffset**: address of the contract to call + - **argsOffset**: memory offset to args (will become the callee's calldata) + - **argsSize**: number of words to pass via callee's calldata + - **retOffset**: destination memory offset specifying where to store the data returned from the callee + - **retSize**: number of words to copy from data returned by callee + - **successOffset**: destination memory offset specifying where to store the call's success (0: failure, 1: success) +- **Expression**: + +{`M[successOffset] = call( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize])`} + +- **Details**: Creates a new (nested) execution context and triggers execution within it until the nested context halts. + Then resumes execution in the current/calling context. A non-existent contract or one with no code will return success. + See ["Nested contract calls"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts. +- **Tag checks**: `T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32` +- **Tag updates**: + +{`T[successOffset] = u8 +T[retOffset:retOffset+retSize] = field`} + +- **Bit-size**: 248 -[![](./images/bit-formats/PORTAL.png)](./images/bit-formats/PORTAL.png) +[![](./images/bit-formats/CALL.png)](./images/bit-formats/CALL.png) -### `CALLDEPTH` (0x34) -Get how many calls deep the current call context is +### `STATICCALL` +Call into another contract, disallowing World State and Accrued Substate modifications -[See in table.](#isa-table-calldepth) +[See in table.](#isa-table-staticcall) -- **Category**: call context +- **Opcode**: 0x33 +- **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = CallContext.calldepth` -- **Details**: Note: security issues with EVM's tx.origin can be resolved by asserting the `calldepth == 0`. -- **Tag updates**: `T[dstOffset] = u8` -- **Bit-size**: 56 + - **gasOffset**: offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee + - **addrOffset**: address of the contract to call + - **argsOffset**: memory offset to args (will become the callee's calldata) + - **argsSize**: number of words to pass via callee's calldata + - **retOffset**: destination memory offset specifying where to store the data returned from the callee + - **retSize**: number of words to copy from data returned by callee + - **successOffset**: destination memory offset specifying where to store the call's success (0: failure, 1: success) +- **Expression**: + +{`M[successOffset] = staticcall( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize])`} + +- **Details**: Same as `CALL`, but disallows World State and Accrued Substate modifications. See ["Nested contract calls"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts. +- **Tag checks**: `T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32` +- **Tag updates**: + +{`T[successOffset] = u8 +T[retOffset:retOffset+retSize] = field`} + +- **Bit-size**: 248 -[![](./images/bit-formats/CALLDEPTH.png)](./images/bit-formats/CALLDEPTH.png) +[![](./images/bit-formats/STATICCALL.png)](./images/bit-formats/STATICCALL.png) -### `L1GAS` (0x35) -Remaining "L1 gas" for this call (after this instruction). +### `RETURN` +Halt execution within this context (without revert), optionally returning some data -[See in table.](#isa-table-l1gas) +[See in table.](#isa-table-return) -- **Category**: latest context +- **Opcode**: 0x34 +- **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = LatestContext.l1Gas` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **retOffset**: memory offset of first word to return + - **retSize**: number of words to return +- **Expression**: + +{`context.contractCallResults.output = M[retOffset:retOffset+retSize] +halt`} + +- **Details**: Return control flow to the calling context/contract. Caller will accept World State and Accrued Substate modifications. See ["Halting"](./avm#halting) to learn more. See ["Nested contract calls"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts. +- **Bit-size**: 88 -[![](./images/bit-formats/L1GAS.png)](./images/bit-formats/L1GAS.png) +[![](./images/bit-formats/RETURN.png)](./images/bit-formats/RETURN.png) -### `L2GAS` (0x36) -Remaining "L2 gas" for this call (after this instruction). +### `REVERT` +Halt execution within this context as `reverted`, optionally returning some data -[See in table.](#isa-table-l2gas) +[See in table.](#isa-table-revert) -- **Category**: latest context +- **Opcode**: 0x35 +- **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **dstOffset**: memory offset specifying where to store operation's result -- **Expression**: `M[dstOffset] = LatestContext.l2Gas` -- **Tag updates**: `T[dstOffset] = u32` -- **Bit-size**: 56 + - **retOffset**: memory offset of first word to return + - **retSize**: number of words to return +- **Expression**: + +{`context.contractCallResults.output = M[retOffset:retOffset+retSize] +context.contractCallResults.reverted = true +halt`} + +- **Details**: Return control flow to the calling context/contract. Caller will reject World State and Accrued Substate modifications. See ["Halting"](./avm#halting) to learn more. See ["Nested contract calls"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts. +- **Bit-size**: 88 -[![](./images/bit-formats/L2GAS.png)](./images/bit-formats/L2GAS.png) +[![](./images/bit-formats/REVERT.png)](./images/bit-formats/REVERT.png) diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/ADD.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/ADD.png index ee1a32d95b7..696324a4c45 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/ADD.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/ADD.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/ADDRESS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/ADDRESS.png index 4314acef2a1..75a307347f3 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/ADDRESS.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/ADDRESS.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/AND.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/AND.png index 9bfc38479f1..fe56f671f42 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/AND.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/AND.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKDAGASLIMIT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKDAGASLIMIT.png new file mode 100644 index 00000000000..d95eac60812 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKDAGASLIMIT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKHEADERBYNUM.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKHEADERBYNUM.png new file mode 100644 index 00000000000..1a83a1d8dc5 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKHEADERBYNUM.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL1GASLIMIT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL1GASLIMIT.png index 20f5ded9390..ba869fff1ec 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL1GASLIMIT.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL1GASLIMIT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL2GASLIMIT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL2GASLIMIT.png index f952f689f04..2eb40c34949 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL2GASLIMIT.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKL2GASLIMIT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKNUMBER.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKNUMBER.png index c7217f8452a..59ea492d9d3 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKNUMBER.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKNUMBER.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKSROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKSROOT.png deleted file mode 100644 index d844d63bb4f..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/BLOCKSROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALL.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALL.png index a0170351666..ac57e52b5bb 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALL.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALL.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDATACOPY.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDATACOPY.png index 133d86a37d9..00a763cb06d 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDATACOPY.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDATACOPY.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDEPTH.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDEPTH.png deleted file mode 100644 index 1cca7c9e725..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLDEPTH.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLER.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLER.png deleted file mode 100644 index dfb24671c96..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CALLER.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CAST.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CAST.png index d663c342ae7..8ee381fba7f 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CAST.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CAST.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CHAINID.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CHAINID.png index d197552c9dc..e7fa8d7b431 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CHAINID.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CHAINID.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CMOV.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CMOV.png index a46692edd84..f90abd3b274 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CMOV.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CMOV.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/COINBASE.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/COINBASE.png index 72e2f88758d..19dd8c4c5a2 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/COINBASE.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/COINBASE.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTCALLDEPTH.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTCALLDEPTH.png new file mode 100644 index 00000000000..6222fe48045 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTCALLDEPTH.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTSROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTSROOT.png deleted file mode 100644 index 47c6cb0f93c..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/CONTRACTSROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/DAGASLEFT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/DAGASLEFT.png new file mode 100644 index 00000000000..96f93a3418e Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/DAGASLEFT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/DIV.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/DIV.png index 58fee0f6853..a87e44962f3 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/DIV.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/DIV.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNOTEHASH.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNOTEHASH.png index fd31987d317..036785120e8 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNOTEHASH.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNOTEHASH.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNULLIFIER.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNULLIFIER.png index 50c4328012c..23ba0e857e3 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNULLIFIER.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITNULLIFIER.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITUNENCRYPTEDLOG.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITUNENCRYPTEDLOG.png new file mode 100644 index 00000000000..43ed04808e8 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/EMITUNENCRYPTEDLOG.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/EQ.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/EQ.png index 426d47621b0..4ee5f60980f 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/EQ.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/EQ.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERDAGAS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERDAGAS.png new file mode 100644 index 00000000000..2c1cf3f6e04 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERDAGAS.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL1GAS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL1GAS.png index 428bb22433d..3b31baa617d 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL1GAS.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL1GAS.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL2GAS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL2GAS.png index db94bc190a3..441f9782688 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL2GAS.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/FEEPERL2GAS.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/GLOBALSHASH.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/GLOBALSHASH.png deleted file mode 100644 index 0cea4cc32d0..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/GLOBALSHASH.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/GRANDROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/GRANDROOT.png deleted file mode 100644 index 34d66c5a331..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/GRANDROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/INTERNALRETURN.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/INTERNALRETURN.png new file mode 100644 index 00000000000..56c484afde1 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/INTERNALRETURN.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMP.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMP.png index 9d9fd47b38b..e8e6f02c692 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMP.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMP.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMPI.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMPI.png index 326a7971d4a..8c79533a7d5 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMPI.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/JUMPI.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GAS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GAS.png deleted file mode 100644 index 7ec775889c5..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GAS.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GASLEFT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GASLEFT.png new file mode 100644 index 00000000000..796c3bb25db Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/L1GASLEFT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GAS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GAS.png deleted file mode 100644 index fcf79de2f78..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GAS.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GASLEFT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GASLEFT.png new file mode 100644 index 00000000000..0cb4674b10b Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/L2GASLEFT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/LT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/LT.png index 59927272c47..442a7021a2b 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/LT.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/LT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/LTE.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/LTE.png index 1b0e35cf290..7f2383fdb4d 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/LTE.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/LTE.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/MOV.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/MOV.png index 4d79281a5e3..f1e83baa411 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/MOV.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/MOV.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/MSGSROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/MSGSROOT.png deleted file mode 100644 index d39c81f4564..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/MSGSROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/MUL.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/MUL.png new file mode 100644 index 00000000000..28095b7457b Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/MUL.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/NOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/NOT.png index 34907da432a..6af81369d5a 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/NOT.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/NOT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/NOTESROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/NOTESROOT.png deleted file mode 100644 index 4a8d6b3d9fd..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/NOTESROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/NULLIFIERSROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/NULLIFIERSROOT.png deleted file mode 100644 index fc8d2cd1050..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/NULLIFIERSROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/OR.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/OR.png index d796c0b5488..c1e6256214d 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/OR.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/OR.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/ORIGIN.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/ORIGIN.png index f712ff96084..5b8754356b9 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/ORIGIN.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/ORIGIN.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/PORTAL.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/PORTAL.png index 2aa7a82f203..ff516d75519 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/PORTAL.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/PORTAL.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/PUBLICDATAROOT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/PUBLICDATAROOT.png deleted file mode 100644 index 44ddaf86bc2..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/PUBLICDATAROOT.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/READL1TOL2MSG.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/READL1TOL2MSG.png new file mode 100644 index 00000000000..aa2a43c54e1 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/READL1TOL2MSG.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/REFUNDEE.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/REFUNDEE.png deleted file mode 100644 index 70ccb4c1f5a..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/REFUNDEE.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/RETURN.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/RETURN.png index e1bf7d6a19d..90d42f5ad0f 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/RETURN.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/RETURN.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/REVERT.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/REVERT.png index 67c12bd2d06..01aa918429f 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/REVERT.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/REVERT.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDER.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDER.png new file mode 100644 index 00000000000..0001e161420 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDER.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDL2TOL1MSG.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDL2TOL1MSG.png index 04611cd6a43..253882ebc65 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDL2TOL1MSG.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SENDL2TOL1MSG.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SET.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SET.png index 9d68daa851d..418e88185cd 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SET.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SET.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SHL.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SHL.png index 0c082bc62a6..26064fe61bf 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SHL.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SHL.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SHR.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SHR.png index ed85ae15c1f..d6e76948abe 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SHR.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SHR.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SLOAD.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SLOAD.png index f9c6540667d..05fd89e17ca 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SLOAD.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SLOAD.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SSTORE.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SSTORE.png index 5580d4237a7..14742f8d60e 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SSTORE.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SSTORE.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/STATICCALL.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/STATICCALL.png index e433c5063c3..61ba39ba7fb 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/STATICCALL.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/STATICCALL.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/STORAGEADDRESS.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/STORAGEADDRESS.png new file mode 100644 index 00000000000..d0455038b2e Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/STORAGEADDRESS.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/SUB.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/SUB.png index e6157763289..647af157ba7 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/SUB.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/SUB.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/TIMESTAMP.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/TIMESTAMP.png index 8ac215faa81..e505abdd032 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/TIMESTAMP.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/TIMESTAMP.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/ULOG.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/ULOG.png deleted file mode 100644 index 1c414f29b53..00000000000 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/ULOG.png and /dev/null differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/VERSION.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/VERSION.png index dc95ff9b5ca..c7cb9e18eef 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/VERSION.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/VERSION.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/XOR.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/XOR.png index 83610f677e9..668629f573f 100644 Binary files a/yellow-paper/docs/public-vm/gen/images/bit-formats/XOR.png and b/yellow-paper/docs/public-vm/gen/images/bit-formats/XOR.png differ diff --git a/yellow-paper/docs/public-vm/gen/images/bit-formats/internalcall.png b/yellow-paper/docs/public-vm/gen/images/bit-formats/internalcall.png new file mode 100644 index 00000000000..8a2930a7fe2 Binary files /dev/null and b/yellow-paper/docs/public-vm/gen/images/bit-formats/internalcall.png differ diff --git a/yellow-paper/docs/public-vm/instruction-set.mdx b/yellow-paper/docs/public-vm/instruction-set.mdx index ce5eb82ffc9..1693295d2de 100644 --- a/yellow-paper/docs/public-vm/instruction-set.mdx +++ b/yellow-paper/docs/public-vm/instruction-set.mdx @@ -1,5 +1,13 @@ # Instruction Set +This page lists all of the instructions supported by the Aztec Virtual Machine (AVM). + +The following notes are relevant to the table and sections below: +- `M[offset]` notation is shorthand for `context.machineState.memory[offset]` +- Any instruction whose description does not mention a program counter change simply increments it: `context.machineState.pc++` +- All instructions update `context.machineState.*GasLeft` as detailed in ["Gas limits and tracking"](./avm#gas-limits-and-tracking) +- Any instruction can lead to an exceptional halt as specified in ["Exceptional halting"](./avm#exceptional-halting) + import GeneratedInstructionSet from "./gen/_InstructionSet.mdx"; diff --git a/yellow-paper/docs/public-vm/state-model.md b/yellow-paper/docs/public-vm/state-model.md index a52bbbe7504..d6087cba3e8 100644 --- a/yellow-paper/docs/public-vm/state-model.md +++ b/yellow-paper/docs/public-vm/state-model.md @@ -52,11 +52,11 @@ Memory addresses must be tagged to be a `u32` type. - `M[X]`: main memory cell at offset `X` - `tag`: a value referring to a memory cell's type (its maximum potential value) - `T[X]`: the tag associated with memory cell at offset `X` -- `in-tag`: an instruction's tag to check input operands against. Present for many but not all instructions. -- `dst-tag`: the target type of a `CAST` instruction, also used to tag the destination memory cell -- `ADD`: shorthand for an `ADD` instruction with `in-tag = X` -- `ADD aOffset bOffset dstOffset`: an full `ADD` instruction with `in-tag = X`. See [here](./instruction-set#isa-section-add) for more details. -- `CAST`: a `CAST` instruction with `dst-tag`: `X`. `CAST` is the only instruction with a `dst-tag`. See [here](./instruction-set#isa-section-cast) for more details. +- `inTag`: an instruction's tag to check input operands against. Present for many but not all instructions. +- `dstTag`: the target type of a `CAST` instruction, also used to tag the destination memory cell +- `ADD`: shorthand for an `ADD` instruction with `inTag = X` +- `ADD aOffset bOffset dstOffset`: an full `ADD` instruction with `inTag = X`. See [here](./instruction-set#isa-section-add) for more details. +- `CAST`: a `CAST` instruction with `dstTag`: `X`. `CAST` is the only instruction with a `dstTag`. See [here](./instruction-set#isa-section-cast) for more details. ### Tags and tagged memory @@ -80,7 +80,7 @@ The purpose of a tag is to inform the VM of the maximum possible length of an op #### Checking input operand tags -Many AVM instructions explicitly operate over range-constrained input parameters (e.g. `ADD`). The maximum allowable value for an instruction's input parameters is defined via an `in-tag` (instruction/input tag). Two potential scenarios result: +Many AVM instructions explicitly operate over range-constrained input parameters (e.g. `ADD`). The maximum allowable value for an instruction's input parameters is defined via an `inTag` (instruction/input tag). Two potential scenarios result: 1. A VM instruction's tag value matches the input parameter tag values 2. A VM instruction's tag value does _not_ match the input parameter tag values @@ -95,8 +95,8 @@ It is required that all VM instructions that write into main memory explicitly d ``` # ADD aOffset bOffset dstOffset -assert T[aOffset] == T[bOffset] == u32 // check inputs against in-tag, revert on mismatch -T[dstOffset] = u32 // tag destination with in-tag +assert T[aOffset] == T[bOffset] == u32 // check inputs against inTag, revert on mismatch +T[dstOffset] = u32 // tag destination with inTag M[dstOffset] = M[aOffset] + M[bOffset] // perform the addition ``` @@ -110,7 +110,7 @@ T[dstOffset] = T[srcOffset] // preserve tag M[dstOffset] = M[srcOffset] // perform the move ``` -Note that `MOV` does not have an `in-tag` and therefore does not need to make any assertions regarding the source memory cell's type. +Note that `MOV` does not have an `inTag` and therefore does not need to make any assertions regarding the source memory cell's type. #### `CAST` and tag conversions @@ -125,7 +125,7 @@ Case 2 is trivial as no additional consistency checks must be performed between ``` # CAST srcOffset dstOffset -T[dstOffset] = u64 // tag destination with dst-tag +T[dstOffset] = u64 // tag destination with dstTag M[dstOffset] = cast(M[srcOffset]) // perform cast ``` diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index ff3fd87fb47..776890efff9 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -15,13 +15,11 @@ const INSTRUCTION_SET_RAW = [ { "id": "add", "Name": "`ADD`", - "Category": "arithmetic", + "Category": "Compute - Arithmetic", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -30,19 +28,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k`", "Summary": "Addition (a + b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "sub", "Name": "`SUB`", - "Category": "arithmetic", + "Category": "Compute - Arithmetic", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -51,19 +47,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k`", "Summary": "Subtraction (a - b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "mul", "Name": "`MUL`", - "Category": "arithmetic", + "Category": "Compute - Arithmetic", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -72,19 +66,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k`", "Summary": "Multiplication (a * b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "div", "Name": "`DIV`", - "Category": "arithmetic", + "Category": "Compute - Arithmetic", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -93,19 +85,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] / M[bOffset]`", "Summary": "Unsigned division (a / b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "eq", "Name": "`EQ`", - "Category": "conditional", + "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -114,19 +104,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0`", "Summary": "Equality check (a == b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "lt", "Name": "`LT`", - "Category": "conditional", + "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -135,19 +123,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0`", "Summary": "Less-than check (a < b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "lte", "Name": "`LTE`", - "Category": "conditional", + "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -156,19 +142,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0`", "Summary": "Less-than-or-equals check (a <= b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "and", "Name": "`AND`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -177,19 +161,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] AND M[bOffset]`", "Summary": "Bitwise AND (a & b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "or", "Name": "`OR`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -198,19 +180,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] OR M[bOffset]`", "Summary": "Bitwise OR (a | b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "xor", "Name": "`XOR`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -219,19 +199,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] XOR M[bOffset]`", "Summary": "Bitwise XOR (a ^ b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "not", "Name": "`NOT`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's input"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, @@ -239,19 +217,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = NOT M[aOffset]`", "Summary": "Bitwise NOT (inversion)", "Details": "", - "Tag checks": "`T[aOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "shl", "Name": "`SHL`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -260,19 +236,17 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] << M[bOffset]`", "Summary": "Bitwise leftward shift (a << b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "shr", "Name": "`SHR`", - "Category": "bitwise", + "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, {"name": "bOffset", "description": "memory offset of the operation's right input"}, @@ -281,816 +255,718 @@ const INSTRUCTION_SET_RAW = [ "Expression": "`M[dstOffset] = M[aOffset] >> M[bOffset]`", "Summary": "Bitwise rightward shift (a >> b)", "Details": "", - "Tag checks": "`T[aOffset] == T[bOffset] == in-tag`", - "Tag updates": "`T[dstOffset] = in-tag`", + "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", + "Tag updates": "`T[dstOffset] = inTag`", }, { "id": "cast", "Name": "`CAST`", - "Category": "types", + "Category": "Type Conversions", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "dst-tag", "description": DST_TAG_DESCRIPTION}, + {"name": "dstTag", "description": DST_TAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ {"name": "aOffset", "description": "memory offset of word to cast"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = cast(M[aOffset])`", + "Expression": "`M[dstOffset] = cast(M[aOffset])`", "Summary": "Type cast", - "Details": "Cast a word in memory based on the `dst-tag` specified in the bytecode. Truncates (`M[dstOffset] = M[aOffset] mod 2^dstsize`) when casting to a smaller type, left-zero-pads when casting to a larger type. See [here](./state-model#cast-and-tag-conversions) for more details.", + "Details": "Cast a word in memory based on the `dstTag` specified in the bytecode. Truncates (`M[dstOffset] = M[aOffset] mod 2^dstsize`) when casting to a smaller type, left-zero-pads when casting to a larger type. See [here](./state-model#cast-and-tag-conversions) for more details.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = dst-tag`", + "Tag updates": "`T[dstOffset] = dstTag`", }, { - "id": "set", - "Name": "`SET`", - "Category": "memory", - "Flags": [ - {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "in-tag", "description": "The [type/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for SET."}, - ], - "#memreads": "0", - "#memwrites": "1", - "Args": [ - {"name": "const", "description": "an N-bit constant value from the bytecode to store in memory (any type except `field`)", "mode": "immediate"}, - {"name": "dstOffset", "description": "memory offset specifying where to store the constant"}, - ], - "Expression": "`M[dstOffset] = const`", - "Summary": "Set a memory word from a constant in the bytecode.", - "Details": "Set memory word at `dstOffset` to `const`'s immediate value. `const`'s bit-size (N) can be 8, 16, 32, 64, or 128 based on `in-tag`. It _cannot be 254 (`field` type)_!", - "Tag checks": "", - "Tag updates": "`T[dstOffset] = in-tag`", - }, - { - "id": "mov", - "Name": "`MOV`", - "Category": "memory", + "id": "address", + "Name": "`ADDRESS`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "srcOffset", "description": "memory offset of word to move"}, - {"name": "dstOffset", "description": "memory offset specifying where to store that word"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = M[srcOffset]`", - "Summary": "Move a word from source memory location to destination`.", + "Expression": "`M[dstOffset] = context.environment.address`", + "Summary": "Get the address of the currently executing l2 contract", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = T[srcOffset]`", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "cmov", - "Name": "`CMOV`", - "Category": "memory", + "id": "storageaddress", + "Name": "`STORAGEADDRESS`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "3", - "#memwrites": "1", "Args": [ - {"name": "aOffset", "description": "memory offset of word 'a' to conditionally move"}, - {"name": "bOffset", "description": "memory offset of word 'b' to conditionally move"}, - {"name": "condOffset", "description": "memory offset of the operations 'conditional' input"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]`", - "Summary": "Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`).", - "Details": "One of two source memory locations is chosen based on the condition. `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type.", + "Expression": "`M[dstOffset] = context.environment.storageAddress`", + "Summary": "Get the _storage_ address of the currently executing context", + "Details": "The storage address is used for public storage accesses.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]`", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "calldatacopy", - "Name": "`CALLDATACOPY`", - "Category": "contract calls", + "id": "origin", + "Name": "`ORIGIN`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "`s1`", - "#memwrites": "`s1`", "Args": [ - {"name": "cdOffset", "description": "offset into calldata to copy from"}, - {"name": "copySize", "description": "number of words to copy", "mode": "immediate", "type": "u32"}, - {"name": "dstOffset", "description": "memory offset specifying where to copy the first word to"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize]`", - "Summary": "Copy calldata into memory.", - "Details": "Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally.", + "Expression": "`M[dstOffset] = context.environment.origin`", + "Summary": "Get the transaction's origination address", + "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset:dstOffset+copySize] = field`", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "sload", - "Name": "`SLOAD`", - "Category": "storage & messaging", + "id": "sender", + "Name": "`SENDER`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "1", "Args": [ - {"name": "slotOffset", "description": "memory offset of the storage slot to load from"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = storage[M[slotOffset]]`", - "Summary": "Load a word from storage.", - "Details": "Load a word from this contract's persistent public storage into memory.", + "Expression": "`M[dstOffset] = context.environment.sender`", + "Summary": "Get the address of the sender (caller of the current context)", + "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "sstore", - "Name": "`SSTORE`", - "Category": "storage & messaging", + "id": "portal", + "Name": "`PORTAL`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "2", - "#memwrites": "0", "Args": [ - {"name": "srcOffset", "description": "memory offset of the word to store"}, - {"name": "slotOffset", "description": "memory offset containing the storage slot to store to"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`storage[M[slotOffset]] = M[srcOffset]`", - "Summary": "Write a word to storage.", - "Details": "Store a word from memory into this contract's persistent public storage.", + "Expression": "`M[dstOffset] = context.environment.portal`", + "Summary": "Get the address of the l1 portal contract", + "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "emitnotehash", - "Name": "`EMITNOTEHASH`", - "Category": "storage & messaging", + "id": "feeperl1gas", + "Name": "`FEEPERL1GAS`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "0", "Args": [ - {"name": "noteHashOffset", "description": "memory offset of the note hash"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": `emitNoteHash(M[contentOffset])`, - "Summary": "Emit a new note hash to be inserted into the notes tree", + "Expression": "`M[dstOffset] = context.environment.feePerL1Gas`", + "Summary": "Get the fee to be paid per \"L1 gas\" - constant for entire transaction", "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "emitnullifier", - "Name": "`EMITNULLIFIER`", - "Category": "storage & messaging", + "id": "feeperl2gas", + "Name": "`FEEPERL2GAS`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "0", "Args": [ - {"name": "nullifierOffset", "description": "memory offset of nullifier"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": `emitNullifier(M[nullifierOffset])`, - "Summary": "Emit a new nullifier to be inserted into the nullifier tree", + "Expression": "`M[dstOffset] = context.environment.feePerL2Gas`", + "Summary": "Get the fee to be paid per \"L2 gas\" - constant for entire transaction", "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "sendl2tol1msg", - "Name": "`SENDL2TOL1MSG`", - "Category": "storage & messaging", + "id": "feeperdagas", + "Name": "`FEEPERDAGAS`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "0", "Args": [ - {"name": "contentOffset", "description": "memory offset of the message content"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": `sendL2ToL1Message(M[contentOffset])`, - "Summary": "Send an L2-to-L1 message", + "Expression": "`M[dstOffset] = context.environment.feePerDaGas`", + "Summary": "Get the fee to be paid per \"DA gas\" - constant for entire transaction", "Details": "", "Tag checks": "", - "Tag updates": "", - }, - { - "id": "jump", - "Name": "`JUMP`", - "Category": "control", - "Flags": [], - "#memreads": "0", - "#memwrites": "0", - "Args": [ - {"name": "loc", "description": "target location to jump to", "mode": "immediate", "type": "u32"}, - ], - "Expression": "`PC = loc`", - "Summary": "Jump to a location in the bytecode.", - "Details": "Target location is an immediate value (a constant in the bytecode).", - "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "jumpi", - "Name": "`JUMPI`", - "Category": "control", + "id": "contractcalldepth", + "Name": "`CONTRACTCALLDEPTH`", + "Category": "Execution Environment", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "3", - "#memwrites": "0", "Args": [ - {"name": "loc", "description": "target location conditionally jump to", "mode": "immediate", "type": "u32"}, - {"name": "condOffset", "description": "memory offset of the operations 'conditional' input"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`PC = M[condOffset] > 0 ? loc : PC`", - "Summary": "Conditionally jump to a location in the bytecode.", - "Details": "Target location is an immediate value (a constant in the bytecode). `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type.", + "Expression": "`M[dstOffset] = context.environment.contractCallDepth`", + "Summary": "Get how many contract calls deep the current call context is", + "Details": "Note: security issues with EVM's tx.origin can be resolved by asserting `calldepth == 0`.", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u8`", }, { - "id": "return", - "Name": "`RETURN`", - "Category": "contract calls", + "id": "chainid", + "Name": "`CHAINID`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "`s1`", - "#memwrites": "0", "Args": [ - {"name": "retOffset", "description": "memory offset of first word to return"}, - {"name": "retSize", "description": "number of words to return", "mode": "immediate", "type": "u32"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`return(M[retOffset:retOffset+retSize])`", - "Summary": "Halt execution with `success`, optionally returning some data.", - "Details": "Return control flow to the calling context/contract.", + "Expression": "`M[dstOffset] = context.environment.globals.chainId`", + "Summary": "Get this rollup's L1 chain ID", + "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "revert", - "Name": "`REVERT`", - "Category": "contract calls", + "id": "version", + "Name": "`VERSION`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "`s1`", - "#memwrites": "0", "Args": [ - {"name": "retOffset", "description": "memory offset of first word to return"}, - {"name": "retSize", "description": "number of words to return", "mode": "immediate", "type": "u32"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`revert(M[retOffset:retOffset+retSize])`", - "Summary": "Halt execution with `failure`, reverting state changes and optionally returning some data.", - "Details": "Return control flow to the calling context/contract.", + "Expression": "`M[dstOffset] = context.environment.globals.version`", + "Summary": "Get this rollup's L2 version ID", + "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "call", - "Name": "`CALL`", - "Category": "contract calls", + "id": "blocknumber", + "Name": "`BLOCKNUMBER`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "7", - "#memwrites": "`1+retSize`", "Args": [ - {"name": "gasOffset", "description": "offset to two words containing `{l1Gas, l2Gas}`: amount of L1 and L2 gas to provide to the callee"}, - {"name": "addrOffset", "description": "address of the contract to call"}, - {"name": "argsOffset", "description": "memory offset to args (will become the callee's calldata)"}, - {"name": "argsSize", "description": "number of words to pass via callee's calldata", "mode": "immediate", "type": "u32"}, - {"name": "retOffset", "description": "destination memory offset specifying where to store the data returned from the callee"}, - {"name": "retSize", "description": "number of words to copy from data returned by callee", "mode": "immediate", "type": "u32"}, - {"name": "successOffset", "description": "destination memory offset specifying where to store the call's success (0: failure, 1: success)", "type": "u8"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression":` -M[successOffset] = call( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize]) -`, - "Summary": "Call into another contract.", - "Details": `Creates a new CallContext, triggers execution of the corresponding contract code, - and then resumes execution in the current CallContext. A non-existent contract or one - with no code will return success. Nested call has an incremented \`CallContext.calldepth\`.`, - "Tag checks": "`T[gasOffset] == T[gasOffset+1] == u32`", - "Tag updates": ` -T[successOffset] = u8 -T[retOffset:retOffset+retSize] = field -`, + "Expression": "`M[dstOffset] = context.environment.globals.blocknumber`", + "Summary": "Get this L2 block's number", + "Details": "", + "Tag checks": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "staticcall", - "Name": "`STATICCALL`", - "Category": "contract calls", + "id": "timestamp", + "Name": "`TIMESTAMP`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "7", - "#memwrites": "`1+retSize`", "Args": [ - {"name": "gasOffset", "description": "offset to two words containing `{l1Gas, l2Gas}`: amount of L1 and L2 gas to provide to the callee"}, - {"name": "addrOffset", "description": "address of the contract to call"}, - {"name": "argsOffset", "description": "memory offset to args (will become the callee's calldata)"}, - {"name": "argsSize", "description": "number of words to pass via callee's calldata", "mode": "immediate", "type": "u32"}, - {"name": "retOffset", "description": "destination memory offset specifying where to store the data returned from the callee"}, - {"name": "retSize", "description": "number of words to copy from data returned by callee", "mode": "immediate", "type": "u32"}, - {"name": "successOffset", "description": "destination memory offset specifying where to store the call's success (0: failure, 1: success)", "type": "u8"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": ` -M[successOffset] = staticcall( - M[gasOffset], M[gasOffset+1], M[addrOffset], - M[argsOffset], M[argsSize], - M[retOffset], M[retSize]) -`, - "Summary": "Call into another contract, disallowing persistent state modifications.", - "Details": "Same as `CALL`, but the callee is cannot modify persistent state. Disallowed instructions are `SSTORE`, `ULOG`, `CALL`.", - "Tag checks": "`T[gasOffset] == T[gasOffset+1] == u32`", - "Tag updates": ` -T[successOffset] = u8 -T[retOffset:retOffset+retSize] = field -`, + "Expression": "`M[dstOffset] = context.environment.globals.timestamp`", + "Summary": "Get this L2 block's timestamp", + "Details": "", + "Tag checks": "", + "Tag updates": "`T[dstOffset] = u64`", }, { - "id": "ulog", - "Name": "`ULOG`", - "Category": "logging", + "id": "coinbase", + "Name": "`COINBASE`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "`s1`", - "#memwrites": "0", "Args": [ - {"name": "logOffset", "description": "memory offset of the data to log"}, - {"name": "logSize", "description": "number of words to log", "mode": "immediate", "type": "u32"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`ulog(M[logOffset:logOffset+logSize])`", - "Summary": "Emit an unencrypted log with data from the `field` memory page", + "Expression": "`M[dstOffset] = context.environment.globals.coinbase`", + "Summary": "Get the block's beneficiary address", "Details": "", "Tag checks": "", - "Tag updates": "", + "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "chainid", - "Name": "`CHAINID`", - "Category": "block info", + "id": "blockl1gaslimit", + "Name": "`BLOCKL1GASLIMIT`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.chainId`", - "Summary": "Get this rollup's L1 chain ID", + "Expression": "`M[dstOffset] = context.environment.globals.l1GasLimit`", + "Summary": "Total amount of \"L1 gas\" that a block can consume", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "version", - "Name": "`VERSION`", - "Category": "block info", + "id": "blockl2gaslimit", + "Name": "`BLOCKL2GASLIMIT`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.version`", - "Summary": "Get this rollup's L2 version ID", + "Expression": "`M[dstOffset] = context.environment.globals.l2GasLimit`", + "Summary": "Total amount of \"L2 gas\" that a block can consume", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "blocknumber", - "Name": "`BLOCKNUMBER`", - "Category": "block info", + "id": "blockdagaslimit", + "Name": "`BLOCKDAGASLIMIT`", + "Category": "Execution Environment - Globals", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.blocknumber`", - "Summary": "Get this block's number", + "Expression": "`M[dstOffset] = context.environment.globals.daGasLimit`", + "Summary": "Total amount of \"DA gas\" that a block can consume", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "timestamp", - "Name": "`TIMESTAMP`", - "Category": "block info", + "id": "calldatacopy", + "Name": "`CALLDATACOPY`", + "Category": "Execution Environment - Calldata", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "cdOffset", "description": "offset into calldata to copy from"}, + {"name": "copySize", "description": "number of words to copy", "mode": "immediate", "type": "u32"}, + {"name": "dstOffset", "description": "memory offset specifying where to copy the first word to"}, ], - "Expression": "`M[dstOffset] = Globals.timestamp`", - "Summary": "Get this L2 block's timestamp", - "Details": "", + "Expression": "`M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]`", + "Summary": "Copy calldata into memory", + "Details": "Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u64`", + "Tag updates": "`T[dstOffset:dstOffset+copySize] = field`", }, { - "id": "coinbase", - "Name": "`COINBASE`", - "Category": "block info", + "id": "l1gasleft", + "Name": "`L1GASLEFT`", + "Category": "Machine State - Gas", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.coinbase`", - "Summary": "Get the block's beneficiary address", + "Expression": "`M[dstOffset] = context.machineState.l1GasLeft`", + "Summary": "Remaining \"L1 gas\" for this call (after this instruction)", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "blockl1gaslimit", - "Name": "`BLOCKL1GASLIMIT`", - "Category": "block info", + "id": "l2gasleft", + "Name": "`L2GASLEFT`", + "Category": "Machine State - Gas", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.l1GasLimit`", - "Summary": "Total amount of \"L1 gas\" that a block can consume", + "Expression": "`M[dstOffset] = context.MachineState.l2GasLeft`", + "Summary": "Remaining \"L2 gas\" for this call (after this instruction)", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "blockl2gaslimit", - "Name": "`BLOCKL2GASLIMIT`", - "Category": "block info", + "id": "dagasleft", + "Name": "`DAGASLEFT`", + "Category": "Machine State - Gas", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = Globals.l2GasLimit`", - "Summary": "Total amount of \"L2 gas\" that a block can consume", + "Expression": "`M[dstOffset] = context.machineState.daGasLeft`", + "Summary": "Remaining \"DA gas\" for this call (after this instruction)", "Details": "", "Tag checks": "", "Tag updates": "`T[dstOffset] = u32`", }, { - "id": "notesroot", - "Name": "`NOTESROOT`", - "Category": "historical access", - "Flags": [ - {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - ], - "#memreads": "1", - "#memwrites": "1", + "id": "jump", + "Name": "`JUMP`", + "Category": "Machine State - Control Flow", + "Flags": [], "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "loc", "description": "target location to jump to", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].note_hash_tree_root`", - "Summary": "Get the historical note-hash tree root as of the specified block number.", - "Details": "", + "Expression": "`context.machineState.pc = loc`", + "Summary": "Jump to a location in the bytecode", + "Details": "Target location is an immediate value (a constant in the bytecode).", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "", }, { - "id": "nullroot", - "Name": "`NULLIFIERSROOT`", - "Category": "historical access", + "id": "jumpi", + "Name": "`JUMPI`", + "Category": "Machine State - Control Flow", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "loc", "description": "target location conditionally jump to", "mode": "immediate", "type": "u32"}, + {"name": "condOffset", "description": "memory offset of the operations 'conditional' input"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].nullifier_tree_root`", - "Summary": "Get the historical nullifier tree root as of the specified block number.", - "Details": "", + "Expression": "`context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc`", + "Summary": "Conditionally jump to a location in the bytecode", + "Details": "Target location is an immediate value (a constant in the bytecode). `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "", }, { - "id": "contractsroot", - "Name": "`CONTRACTSROOT`", - "Category": "historical access", - "Flags": [ - {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - ], - "#memreads": "1", - "#memwrites": "1", + "id": "internalcall", + "Name": "`INTERNALCALL`", + "Category": "Machine State - Control Flow", + "Flags": [], "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "loc", "description": "target location to jump/call to", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].contracts_tree_root`", - "Summary": "Get the historical contracts tree root as of the specified block number.", + "Expression": ` +context.machineState.internalCallStack.push(context.machineState.pc) +context.machineState.pc = loc +`, + "Summary": "Make an internal call. Push the current PC to the internal call stack and jump to the target location.", + "Details": "Target location is an immediate value (a constant in the bytecode).", + "Tag checks": "", + "Tag updates": "", + }, + { + "id": "internalreturn", + "Name": "`INTERNALRETURN`", + "Category": "Machine State - Control Flow", + "Flags": [], + "Args": [], + "Expression": "`context.machineState.pc = context.machineState.internalCallStack.pop()`", + "Summary": "Return from an internal call. Pop from the internal call stack and jump to the popped location.", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "", }, { - "id": "msgsroot", - "Name": "`MSGSROOT`", - "Category": "historical access", + "id": "set", + "Name": "`SET`", + "Category": "Machine State - Memory", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, + {"name": "inTag", "description": "The [type/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for SET."}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "const", "description": "an N-bit constant value from the bytecode to store in memory (any type except `field`)", "mode": "immediate"}, + {"name": "dstOffset", "description": "memory offset specifying where to store the constant"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].l1_to_l2_message_tree_root`", - "Summary": "Get the historical l1-to-l2 message tree root as of the specified block number.", - "Details": "", + "Expression": "`M[dstOffset] = const`", + "Summary": "Set a memory word from a constant in the bytecode", + "Details": "Set memory word at `dstOffset` to `const`'s immediate value. `const`'s bit-size (N) can be 8, 16, 32, 64, or 128 based on `inTag`. It _cannot be 254 (`field` type)_!", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "`T[dstOffset] = inTag`", }, { - "id": "publicdataroot", - "Name": "`PUBLICDATAROOT`", - "Category": "historical access", + "id": "mov", + "Name": "`MOV`", + "Category": "Machine State - Memory", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "srcOffset", "description": "memory offset of word to move"}, + {"name": "dstOffset", "description": "memory offset specifying where to store that word"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].public_data_tree_root`", - "Summary": "Get the historical public data tree root as of the specified block number.", + "Expression": "`M[dstOffset] = M[srcOffset]`", + "Summary": "Move a word from source memory location to destination", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "`T[dstOffset] = T[srcOffset]`", }, { - "id": "globalshash", - "Name": "`GLOBALSHASH`", - "Category": "historical access", + "id": "cmov", + "Name": "`CMOV`", + "Category": "Machine State - Memory", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, + {"name": "aOffset", "description": "memory offset of word 'a' to conditionally move"}, + {"name": "bOffset", "description": "memory offset of word 'b' to conditionally move"}, + {"name": "condOffset", "description": "memory offset of the operations 'conditional' input"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].global_variables_hash`", - "Summary": "Get the historical global variables hash as of the specified block number.", - "Details": "", + "Expression": "`M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]`", + "Summary": "Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`)", + "Details": "One of two source memory locations is chosen based on the condition. `T[condOffset]` is not checked because the greater-than-zero suboperation is the same regardless of type.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "`T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]`", }, { - "id": "blocksroot", - "Name": "`BLOCKSROOT`", - "Category": "historical access", + "id": "blockheaderbynum", + "Name": "`BLOCKHEADERBYNUM`", + "Category": "World State", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ {"name": "blockNumOffset", "description": "memory offset of the block number input"}, - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result's 0th word"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].archive_root`", - "Summary": "Get the historical blocks tree root as of the specified block number.", + "Expression": "`M[dstOffset:dstOffset+BLOCK_HEADER_LENGTH] = context.worldState.blockHeader[M[blockNumOffset]]`", + "Summary": "Get the block header as of the specified block number", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = field`", + "Tag updates": "`T[dstOffset:dstOffset+BLOCK_HEADER_LENGTh] = field`", }, { - "id": "grandroot", - "Name": "`GRANDROOT`", - "Category": "historical access", + "id": "sload", + "Name": "`SLOAD`", + "Category": "World State - Public Storage", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "1", - "#memwrites": "1", "Args": [ - {"name": "blockNumOffset", "description": "memory offset of the block number input"}, + {"name": "slotOffset", "description": "memory offset of the storage slot to load from"}, {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], - "Expression": "`M[dstOffset] = HistoricalBlockData[M[blockNumOffset]].grandfather_tree_root`", - "Summary": "Get the historical grandfather tree root as of the specified block number.", - "Details": "", + "Expression": "`M[dstOffset] = context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]]`", + "Summary": "Load a word from storage", + "Details": "Load a word from this contract's persistent public storage into memory.", "Tag checks": "", "Tag updates": "`T[dstOffset] = field`", }, { - "id": "origin", - "Name": "`ORIGIN`", - "Category": "tx context", + "id": "sstore", + "Name": "`SSTORE`", + "Category": "World State - Public Storage", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "srcOffset", "description": "memory offset of the word to store"}, + {"name": "slotOffset", "description": "memory offset containing the storage slot to store to"}, ], - "Expression": "`M[dstOffset] = TxContext.origin`", - "Summary": "Get the transaction's origination address", - "Details": "", + "Expression": "`context.worldState.publicStorage[context.environment.storageAddress, M[slotOffset]] = M[srcOffset]`", + "Summary": "Write a word to storage", + "Details": "Store a word from memory into this contract's persistent public storage.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "refundee", - "Name": "`REFUNDEE`", - "Category": "tx context", + "id": "readl1tol2msg", + "Name": "`READL1TOL2MSG`", + "Category": "World State - Messaging", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "msgKeyOffset", "description": "memory offset of the message's key"}, + {"name": "dstOffset", "description": "memory offset to place the 0th word of the message content"}, + {"name": "msgSize", "description": "number of words in the message", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = TxContext.refundee`", - "Summary": "The recipient of fee refunds for this transaction", + "Expression": "`M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages(M[msgKeyOffset])`", + "Summary": "Reads an L1-to-L2 message", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "`T[dstOffset:dstOffset+msgSize] = field`", }, { - "id": "feeperl1gas", - "Name": "`FEEPERL1GAS`", - "Category": "tx context", + "id": "sendl2tol1msg", + "Name": "`SENDL2TOL1MSG`", + "Category": "World State - Messaging", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "msgOffset", "description": "memory offset of the message content"}, + {"name": "msgSize", "description": "number of words in the message", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = TxContext.feePerL1Gas`", - "Summary": "The fee to be paid per \"L1 gas\" - set by the transaction's original caller", + "Expression": "`context.worldState.l2ToL1Messages.append(M[msgOffset:msgOffset+msgSize])`", + "Summary": "Send an L2-to-L1 message", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "feeperl2gas", - "Name": "`FEEPERL2GAS`", - "Category": "tx context", + "id": "emitnotehash", + "Name": "`EMITNOTEHASH`", + "Category": "World State - Notes & Nullifiers", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "noteHashOffset", "description": "memory offset of the note hash"}, ], - "Expression": "`M[dstOffset] = TxContext.feePerL2Gas`", - "Summary": "The fee to be paid per \"L2 gas\" - set by the transaction's original caller", + "Expression": "`context.worldState.newHashes.append(M[noteHashOffset])`", + "Summary": "Emit a new note hash to be inserted into the notes tree", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "caller", - "Name": "`CALLER`", - "Category": "call context", + "id": "emitnullifier", + "Name": "`EMITNULLIFIER`", + "Category": "World State - Notes & Nullifiers", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "nullifierOffset", "description": "memory offset of nullifier"}, ], - "Expression": "`M[dstOffset] = CallContext.sender`", - "Summary": "Get the address of the sender (the caller's context)", + "Expression": "`context.worldState.nullifiers.append(M[nullifierOffset])`", + "Summary": "Emit a new nullifier to be inserted into the nullifier tree", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "address", - "Name": "`ADDRESS`", - "Category": "call context", + "id": "emitunencryptedlog", + "Name": "`EMITUNENCRYPTEDLOG`", + "Category": "Accrued Substate - Logging", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "logOffset", "description": "memory offset of the data to log"}, + {"name": "logSize", "description": "number of words to log", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = CallContext.storageContractAddress`", - "Summary": "Get the address of the currently executing l2 contract", + "Expression": "`context.accruedSubstate.unencryptedLogs.append(M[logOffset:logOffset+logSize])`", + "Summary": "Emit an unencrypted log", "Details": "", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "portal", - "Name": "`PORTAL`", - "Category": "call context", + "id": "call", + "Name": "`CALL`", + "Category": "Control Flow - Contract Calls", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "gasOffset", "description": "offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee"}, + {"name": "addrOffset", "description": "address of the contract to call"}, + {"name": "argsOffset", "description": "memory offset to args (will become the callee's calldata)"}, + {"name": "argsSize", "description": "number of words to pass via callee's calldata", "mode": "immediate", "type": "u32"}, + {"name": "retOffset", "description": "destination memory offset specifying where to store the data returned from the callee"}, + {"name": "retSize", "description": "number of words to copy from data returned by callee", "mode": "immediate", "type": "u32"}, + {"name": "successOffset", "description": "destination memory offset specifying where to store the call's success (0: failure, 1: success)", "type": "u8"}, ], - "Expression": "`M[dstOffset] = CallContext.portalAddress`", - "Summary": "Get the address of the l1 portal contract", - "Details": "", - "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Expression":` +M[successOffset] = call( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize]) +`, + "Summary": "Call into another contract", + "Details": `Creates a new (nested) execution context and triggers execution within it until the nested context halts. + Then resumes execution in the current/calling context. A non-existent contract or one with no code will return success. + See [\"Nested contract calls\"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts.`, + "Tag checks": "`T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32`", + "Tag updates": ` +T[successOffset] = u8 +T[retOffset:retOffset+retSize] = field +`, }, { - "id": "calldepth", - "Name": "`CALLDEPTH`", - "Category": "call context", + "id": "staticcall", + "Name": "`STATICCALL`", + "Category": "Control Flow - Contract Calls", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "gasOffset", "description": "offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee"}, + {"name": "addrOffset", "description": "address of the contract to call"}, + {"name": "argsOffset", "description": "memory offset to args (will become the callee's calldata)"}, + {"name": "argsSize", "description": "number of words to pass via callee's calldata", "mode": "immediate", "type": "u32"}, + {"name": "retOffset", "description": "destination memory offset specifying where to store the data returned from the callee"}, + {"name": "retSize", "description": "number of words to copy from data returned by callee", "mode": "immediate", "type": "u32"}, + {"name": "successOffset", "description": "destination memory offset specifying where to store the call's success (0: failure, 1: success)", "type": "u8"}, ], - "Expression": "`M[dstOffset] = CallContext.calldepth`", - "Summary": "Get how many calls deep the current call context is", - "Details": "Note: security issues with EVM's tx.origin can be resolved by asserting the `calldepth == 0`.", - "Tag checks": "", - "Tag updates": "`T[dstOffset] = u8`", + "Expression": ` +M[successOffset] = staticcall( + M[gasOffset], M[gasOffset+1], M[gasOffset+2], + M[addrOffset], + M[argsOffset], M[argsSize], + M[retOffset], M[retSize]) +`, + "Summary": "Call into another contract, disallowing World State and Accrued Substate modifications", + "Details": "Same as `CALL`, but disallows World State and Accrued Substate modifications. See [\"Nested contract calls\"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts.", + "Tag checks": "`T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32`", + "Tag updates": ` +T[successOffset] = u8 +T[retOffset:retOffset+retSize] = field +`, }, { - "id": "l1gas", - "Name": "`L1GAS`", - "Category": "latest context", + "id": "return", + "Name": "`RETURN`", + "Category": "Control Flow - Contract Calls", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "retOffset", "description": "memory offset of first word to return"}, + {"name": "retSize", "description": "number of words to return", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = LatestContext.l1Gas`", - "Summary": "Remaining \"L1 gas\" for this call (after this instruction).", - "Details": "", + "Expression": ` +context.contractCallResults.output = M[retOffset:retOffset+retSize] +halt +`, + "Summary": "Halt execution within this context (without revert), optionally returning some data", + "Details": "Return control flow to the calling context/contract. Caller will accept World State and Accrued Substate modifications. See [\"Halting\"](./avm#halting) to learn more. See [\"Nested contract calls\"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, { - "id": "l2gas", - "Name": "`L2GAS`", - "Category": "latest context", + "id": "revert", + "Name": "`REVERT`", + "Category": "Control Flow - Contract Calls", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], - "#memreads": "0", - "#memwrites": "1", "Args": [ - {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + {"name": "retOffset", "description": "memory offset of first word to return"}, + {"name": "retSize", "description": "number of words to return", "mode": "immediate", "type": "u32"}, ], - "Expression": "`M[dstOffset] = LatestContext.l2Gas`", - "Summary": "Remaining \"L2 gas\" for this call (after this instruction).", - "Details": "", + "Expression": ` +context.contractCallResults.output = M[retOffset:retOffset+retSize] +context.contractCallResults.reverted = true +halt +`, + "Summary": "Halt execution within this context as `reverted`, optionally returning some data", + "Details": "Return control flow to the calling context/contract. Caller will reject World State and Accrued Substate modifications. See [\"Halting\"](./avm#halting) to learn more. See [\"Nested contract calls\"](./avm#nested-contract-calls) to see how the caller updates its context after the nested call halts.", "Tag checks": "", - "Tag updates": "`T[dstOffset] = u32`", + "Tag updates": "", }, ]; const INSTRUCTION_SET = INSTRUCTION_SET_RAW.map((instr) => {instr['Bit-size'] = instructionSize(instr); return instr;}); diff --git a/yellow-paper/src/preprocess/InstructionSet/genMarkdown.js b/yellow-paper/src/preprocess/InstructionSet/genMarkdown.js index e26940ef03f..fbb9792b111 100644 --- a/yellow-paper/src/preprocess/InstructionSet/genMarkdown.js +++ b/yellow-paper/src/preprocess/InstructionSet/genMarkdown.js @@ -86,9 +86,10 @@ function markdownInstructionSetSection(pathToGenDir) { for (let i = 0; i < INSTRUCTION_SET.length; i++) { const instr = INSTRUCTION_SET[i]; const name = instr['Name']; - let subsection = `### ${name} (${toOpcode(i)})\n`; + let subsection = `### ${name}\n`; subsection += `${instr['Summary']}\n\n`; subsection += `[See in table.](#isa-table-${instr['id']})\n\n`; + subsection += `- **Opcode**: ${toOpcode(i)}\n`; for (let t = 0; t < TOPICS_IN_SECTIONS.length; t++) { const topic = TOPICS_IN_SECTIONS[t]; let field = instr[topic];