Skip to content

Commit

Permalink
docs(yellowpaper): AVM call instructions, split out sections, clean…
Browse files Browse the repository at this point in the history
…up (#4594)
  • Loading branch information
dbanks12 authored Feb 15, 2024
1 parent 6d47841 commit e63f022
Show file tree
Hide file tree
Showing 23 changed files with 1,054 additions and 608 deletions.
2 changes: 2 additions & 0 deletions avm-transpiler/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub enum AvmOpcode {
// Control Flow - Contract Calls
CALL,
STATICCALL,
DELEGATECALL,
RETURN,
REVERT,

Expand Down Expand Up @@ -163,6 +164,7 @@ impl AvmOpcode {
// Control Flow - Contract Calls
AvmOpcode::CALL => "CALL",
AvmOpcode::STATICCALL => "STATICCALL",
AvmOpcode::DELEGATECALL => "DELEGATECALL",
AvmOpcode::RETURN => "RETURN",
AvmOpcode::REVERT => "REVERT",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const std::unordered_map<OpCode, size_t> Bytecode::OPERANDS_NUM = {
//// Control Flow - Contract Calls
//{ OpCode::CALL, },
//{ OpCode::STATICCALL, },
//{ OpCode::DELEGATECALL, },
{ OpCode::RETURN, 2 },
// { OpCode::REVERT, },

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ enum class OpCode : uint8_t {
// Control Flow - Contract Calls
CALL,
STATICCALL,
DELEGATECALL,
RETURN,
REVERT,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const INSTRUCTION_SET = () =>
// Control Flow - Contract Calls
[Call.opcode, Call],
[StaticCall.opcode, StaticCall],
//[DelegateCall.opcode, DelegateCall],
[Return.opcode, Return],
[Revert.opcode, Revert],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export enum Opcode {
SENDL2TOL1MSG,
CALL,
STATICCALL,
DELEGATECALL,
RETURN,
REVERT,
KECCAK,
Expand Down
2 changes: 1 addition & 1 deletion yellow-paper/docs/contract-deployment/instances.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Specific to private functions:

Specific to public functions:

- The bytecode loaded by the [AVM](../public-vm/avm.md) for the contract matches the `bytecode_commitment` in the contract class, verified using the [bytecode validation circuit](../public-vm/bytecode-validation-circuit.md).
- The bytecode loaded by the [AVM](../public-vm/intro) for the contract matches the `bytecode_commitment` in the contract class, verified using the [bytecode validation circuit](../public-vm/bytecode-validation-circuit).
- The contract Deployment Nullifier has been emitted, or prove that it hasn't, in which case the transaction is expected to revert. This check is done via a merkle (non-)membership proof of the Deployment Nullifier. Note that a public function should be callable in the same transaction in which its contract Deployment Nullifier was emitted.

Note that, since constructors are handled at the application level, the kernel circuit is not required to check the Initialization Nullifier before executing code.
Expand Down
55 changes: 55 additions & 0 deletions yellow-paper/docs/public-vm/_nested-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
The nested call's execution context is derived from the caller's context and the call instruction's arguments.

The following shorthand syntax is used to refer to nested context derivation in the ["Instruction Set"](./instruction-set) and other sections:

```jsx
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }

isStaticCall = instr.opcode == STATICCALL
isDelegateCall = instr.opcode == DELEGATECALL

nestedContext = deriveContext(context, instr.args, isStaticCall, isDelegateCall)
```

Nested context derivation is defined as follows:
```jsx
nestedExecutionEnvironment = ExecutionEnvironment {
origin: context.origin,
sender: isDelegateCall ? context.sender : context.address,
address: M[addrOffset],
storageAddress: isDelegateCall ? context.storageAddress : M[addrOffset],
portal: callingContext.worldState.contracts[M[addrOffset]].portal,
feePerL1Gas: context.environment.feePerL1Gas,
feePerL2Gas: context.environment.feePerL2Gas,
feePerDaGas: context.environment.feePerDaGas,
contractCallDepth: context.contractCallDepth + 1,
contractCallPointer: context.worldStateAccessTrace.contractCalls.length + 1,
globals: context.globals,
isStaticCall: isStaticCall,
isDelegateCall: isDelegateCall,
calldata: context.memory[M[argsOffset]:M[argsOffset]+argsSize],
}

nestedMachineState = MachineState {
l1GasLeft: context.machineState.memory[M[gasOffset]],
l2GasLeft: context.machineState.memory[M[gasOffset+1]],
daGasLeft: context.machineState.memory[M[gasOffset+2]],
pc = 0,
internalCallStack = [], // initialized as empty
memory = [0, ..., 0], // all 2^32 entries are initialized to zero
}
```


```jsx
nestedContext = AvmContext {
environment: nestedExecutionEnvironment,
machineState: nestedMachineState,
worldState: context.worldState,
worldStateAccessTrace: context.worldStateAccessTrace,
accruedSubstate: { [], ... [], }, // all empty
results: {reverted: false, output: []},
}
```

> `M[offset]` notation is shorthand for `context.machineState.memory[offset]`
5 changes: 2 additions & 3 deletions yellow-paper/docs/public-vm/avm-circuit.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ Prior to the VM circuit's execution, a vector is assembled to contain the byteco
Each entry in the bytecode vector will be paired with a call pointer and program counter. This **Bytecode Table** maps a call pointer and program counter to an instruction, and is used by the Instruction Controller to fetch instructions.
> Note: "call pointer" is expanded on in a later section.
Each contract's public bytecode is committed to during contract deployment. As part of the AVM circuit verification algorithm, the bytecode vector (as a concatenation of all relevant contract bytecodes) is verified against the corresponding bytecode commitments. This is expanded on in ["Bytecode Validation Circuit"](./bytecode-validation-circuit.md). While the AVM circuit enforces that the correct instructions are executed according to its bytecode table, the verifier checks that bytecode table against the previously validated bytecode commitments.
Each contract's public bytecode is committed to during contract deployment. As part of the AVM circuit verification algorithm, the bytecode vector (as a concatenation of all relevant contract bytecodes) is verified against the corresponding bytecode commitments. This is expanded on in ["Bytecode Validation Circuit"](./bytecode-validation-circuit). While the AVM circuit enforces that the correct instructions are executed according to its bytecode table, the verifier checks that bytecode table against the previously validated bytecode commitments.

## Instruction Controller
The Instruction Controller's responsibilities include instruction fetching and decoding.

### Instruction fetching
The Instruction Controller's **instruction fetch** mechanism makes use of the bytecode table to determine which instruction to execute based on the call pointer and program counter. Each instruction fetch corresponds to a circuit lookup to enforce that the correct instruction is processed for a given contract and program counter.

The combination of the instruction fetch circuitry, the bytecode table, and the ["Bytecode Validation Circuit"](./bytecode-validation-circuit.md) ensure that VM circuit processes the proper sequence of instructions.
The combination of the instruction fetch circuitry, the bytecode table, and the ["Bytecode Validation Circuit"](./bytecode-validation-circuit) ensure that VM circuit processes the proper sequence of instructions.

### Instruction decoding and sub-operations
An instruction (its opcode, flags, and arguments) represents some high-level VM operation. For example, an `ADD` instruction says "add two items from memory and store the result in memory". The Instruction Controller **instruction decode** mechanism decodes instructions into sub-operations. While an instruction likely requires many circuit components, a **sub-operation** is a smaller task that can be fed to just one VM circuit component for processing. By decoding an instruction into sub-operations, the VM circuit translates high-level instructions into smaller achievable tasks. To continue with the `ADD` example, it would translate "add two items from memory and store the result in memory" to "load an item from memory, load another item from memory, add them, and store the result to memory."
Expand Down Expand Up @@ -192,7 +192,6 @@ AvmSessionPublicInputs {
sessionResults: AvmSessionResults,
}
```
> The `ExecutionEnvironment` structure is defined in [the AVM's high level specification](./avm.md). `initialEnvironment` here omits `calldata` and `bytecode`.

> The `WorldStateAccessTrace` and `AccruedSubstate` types are defined in ["State"](./state). Their vectors are assigned constant/maximum lengths when used as circuit inputs.
Expand Down
Loading

0 comments on commit e63f022

Please sign in to comment.