Skip to content

Commit

Permalink
Remove delegate call from public
Browse files Browse the repository at this point in the history
  • Loading branch information
dbanks12 committed Sep 4, 2024
1 parent d6ebe3e commit e6577e5
Show file tree
Hide file tree
Showing 47 changed files with 56 additions and 593 deletions.
2 changes: 0 additions & 2 deletions avm-transpiler/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ pub enum AvmOpcode {
// External calls
CALL,
STATICCALL,
DELEGATECALL,
RETURN,
REVERT,
// Misc
Expand Down Expand Up @@ -157,7 +156,6 @@ 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 @@ -138,7 +138,6 @@ const std::unordered_map<OpCode, std::vector<OperandType>> OPCODE_WIRE_FORMAT =
// Control Flow - Contract Calls
{ OpCode::CALL, external_call_format },
// STATICCALL,
// DELEGATECALL, -- not in simulator
{ OpCode::RETURN, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } },
// REVERT,
{ OpCode::REVERT, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } },
Expand Down
3 changes: 1 addition & 2 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/fixed_gas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ const std::unordered_map<OpCode, FixedGasTable::GasRow> GAS_COST_TABLE = {
{ OpCode::SENDL2TOL1MSG, make_cost(AVM_SENDL2TOL1MSG_BASE_L2_GAS, 0, AVM_SENDL2TOL1MSG_DYN_L2_GAS, 0) },
{ OpCode::CALL, make_cost(AVM_CALL_BASE_L2_GAS, 0, AVM_CALL_DYN_L2_GAS, 0) },
{ OpCode::STATICCALL, make_cost(AVM_STATICCALL_BASE_L2_GAS, 0, AVM_STATICCALL_DYN_L2_GAS, 0) },
{ OpCode::DELEGATECALL, make_cost(AVM_DELEGATECALL_BASE_L2_GAS, 0, AVM_DELEGATECALL_DYN_L2_GAS, 0) },
{ OpCode::RETURN, make_cost(AVM_RETURN_BASE_L2_GAS, 0, AVM_RETURN_DYN_L2_GAS, 0) },
{ OpCode::REVERT, make_cost(AVM_REVERT_BASE_L2_GAS, 0, AVM_REVERT_DYN_L2_GAS, 0) },
{ OpCode::DEBUGLOG, make_cost(AVM_DEBUGLOG_BASE_L2_GAS, 0, AVM_DEBUGLOG_DYN_L2_GAS, 0) },
Expand Down Expand Up @@ -108,4 +107,4 @@ const FixedGasTable& FixedGasTable::get()
return table;
}

} // namespace bb::avm_trace
} // namespace bb::avm_trace
2 changes: 0 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ std::string to_string(OpCode opcode)
return "CALL";
case OpCode::STATICCALL:
return "STATICCALL";
case OpCode::DELEGATECALL:
return "DELEGATECALL";
case OpCode::RETURN:
return "RETURN";
case OpCode::REVERT:
Expand Down
1 change: 0 additions & 1 deletion barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ enum class OpCode : uint8_t {
// Control Flow - Contract Calls
CALL,
STATICCALL,
DELEGATECALL,
RETURN,
REVERT,

Expand Down
2 changes: 0 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@
#define AVM_SENDL2TOL1MSG_BASE_L2_GAS 260
#define AVM_CALL_BASE_L2_GAS 450
#define AVM_STATICCALL_BASE_L2_GAS 450
#define AVM_DELEGATECALL_BASE_L2_GAS 0
#define AVM_RETURN_BASE_L2_GAS 140
#define AVM_REVERT_BASE_L2_GAS 140
#define AVM_DEBUGLOG_BASE_L2_GAS 100
Expand Down Expand Up @@ -179,7 +178,6 @@
#define AVM_SENDL2TOL1MSG_DYN_L2_GAS 0
#define AVM_CALL_DYN_L2_GAS 50
#define AVM_STATICCALL_DYN_L2_GAS 50
#define AVM_DELEGATECALL_DYN_L2_GAS 50
#define AVM_RETURN_DYN_L2_GAS 50
#define AVM_REVERT_DYN_L2_GAS 50
#define AVM_DEBUGLOG_DYN_L2_GAS 0
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/protocol-specs/calls/delegate-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ Isn't this a conflation of instances and classes? A contract address represents
Perhaps the information that's needed for any kind of 'call' needs to be modified. At the moment it's: contract_address, function_selector. Perhaps it needs to become: contract_address, class_id, function_selector? Then, for an ordinary call, the class_id can be checked to match the one 'baked into ' the contract_address. For a delegatecall, the contract_address can be that of the calling contract (i.e. the storage contract address), and the class_id can be the target class?
-->

At the contract level, a caller can initiate a delegate call via a `delegateCallPrivateFunction` or `delegateCallPublicFunction` oracle call. The caller is responsible for asserting that the returned `CallStackItem` has the `is_delegate_call` flag correctly set.
At the contract level, a caller can initiate a delegate call via a `delegateCallPrivateFunction`oracle call. The caller is responsible for asserting that the returned `CallStackItem` has the `is_delegate_call` flag correctly set. Delegate calls to public contract code are not supported.
8 changes: 3 additions & 5 deletions docs/docs/protocol-specs/public-vm/_nested-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@ The following shorthand syntax is used to refer to nested context derivation in
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }

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

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

Nested context derivation is defined as follows:
```jsx
nestedExecutionEnvironment = ExecutionEnvironment {
address: M[addrOffset],
storageAddress: isDelegateCall ? context.storageAddress : M[addrOffset],
sender: isDelegateCall ? context.sender : context.address,
storageAddress: M[addrOffset],
sender: context.address,
functionSelector: context.environment.functionSelector,
transactionFee: context.environment.transactionFee,
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],
}

Expand Down
1 change: 0 additions & 1 deletion docs/docs/protocol-specs/public-vm/avm-circuit.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ AvmSessionInputs {
sender: AztecAddress,
contractCallDepth: field,
isStaticCall: boolean,
isDelegateCall: boolean,
transactionFee: field,
// Initializes Machine State
l2GasLeft: field,
Expand Down
2 changes: 0 additions & 2 deletions docs/docs/protocol-specs/public-vm/context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ A context's **execution environment** remains constant throughout a contract cal
| contractCallPointer | `field` | Uniquely identifies each contract call processed by an AVM session. An initial call is assigned pointer value of 1 (expanded on in the AVM circuit section's ["Call Pointer"](./avm-circuit#call-pointer) subsection). |
| globals | `PublicGlobalVariables` | |
| isStaticCall | `boolean` | |
| isDelegateCall | `boolean` | |
| calldata | `[field; <calldata-length>]` | |

## Contract Call Results
Expand Down Expand Up @@ -79,7 +78,6 @@ INITIAL_EXECUTION_ENVIRONMENT = ExecutionEnvironment {
contractCallPointer: 1,
globals: <current block's global variables>
isStaticCall: PublicCallRequest.CallContext.isStaticCall,
isDelegateCall: PublicCallRequest.CallContext.isDelegateCall,
calldata: PublicCallRequest.args,
}
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/protocol-specs/public-vm/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ An instruction's gas cost is meant to reflect the computational cost of generati
- In addition to the base cost, the cost of an instruction increases with the number of reads and writes to memory. This is affected by the total number of input and outputs: the gas cost for [`AND`](./instruction-set/#isa-section-and) should be greater than that of [`NOT`](./instruction-set/#isa-section-not) since it takes one more input.
- Input parameters flagged as "indirect" require an extra memory access, so these should further increase the gas cost of the instruction.
- The base cost for instructions that operate on a data range of a specified "size" scale in cost with that size, but only if they perform an operation on the data other than copying. For example, [`CALLDATACOPY`](./instruction-set/#isa-section-calldatacopy) copies `copySize` words from `environment.calldata` to `machineState.memory`, so its increased cost is captured by the extra memory accesses. On the other hand, [`SSTORE`](./instruction-set#isa-section-sstore) requires accesses to persistent storage proportional to `srcSize`, so its base cost should also increase.
- The [`CALL`](./instruction-set#isa-section-call)/[`STATICCALL`](./instruction-set#isa-section-staticcall)/[`DELEGATECALL`](./instruction-set#isa-section-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](./nested-calls#updating-the-calling-context-after-nested-call-halts)).
- The [`CALL`](./instruction-set#isa-section-call)/[`STATICCALL`](./instruction-set#isa-section-staticcall) 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](./nested-calls#updating-the-calling-context-after-nested-call-halts)).

> An instruction's gas cost will roughly align with the number of rows it corresponds to in the SNARK execution trace including rows in the sub-operation table, memory table, chiplet tables, etc.
> 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.
> 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`) 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

Expand Down Expand Up @@ -188,13 +188,13 @@ The AVM's exceptional halting conditions area listed below:
1. **Maximum contract call depth (1024) exceeded**
```
assert environment.contractCallDepth <= 1024
assert instructions[machineState.pc].opcode not in {CALL, STATICCALL, DELEGATECALL}
assert instructions[machineState.pc].opcode not in {CALL, STATICCALL}
OR environment.contractCallDepth < 1024
```
1. **Maximum contract call calls per execution request (1024) exceeded**
```
assert worldStateAccessTrace.contractCalls.length <= 1024
assert instructions[machineState.pc].opcode not in {CALL, STATICCALL, DELEGATECALL}
assert instructions[machineState.pc].opcode not in {CALL, STATICCALL}
OR worldStateAccessTrace.contractCalls.length < 1024
```
1. **Maximum internal call depth (1024) exceeded**
Expand Down
77 changes: 9 additions & 68 deletions docs/docs/protocol-specs/public-vm/gen/_instruction-set.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=false)
nestedContext = deriveContext(context, instr.args, isStaticCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock></td>
Expand All @@ -478,28 +478,13 @@ chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=true, isDelegateCall=false)
nestedContext = deriveContext(context, instr.args, isStaticCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock></td>
</tr>
<tr>
<td style={{'text-align': 'center'}}>0x34</td>
<td style={{'text-align': 'center'}}><a id='isa-table-delegatecall'/><Markdown>\[\`DELEGATECALL\`\](#isa-section-delegatecall)</Markdown></td>
<td><Markdown>(UNIMPLEMENTED) Call into another contract, but keep the caller's `sender` and `storageAddress`</Markdown></td>
<td><CodeBlock language="jsx">
{`// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock></td>
</tr>
<tr>
<td style={{'text-align': 'center'}}>0x35</td>
<td style={{'text-align': 'center'}}><a id='isa-table-return'/><Markdown>\[\`RETURN\`\](#isa-section-return)</Markdown></td>
<td><Markdown>Halt execution within this context (without revert), optionally returning some data</Markdown></td>
<td><CodeBlock language="jsx">
Expand All @@ -508,7 +493,7 @@ halt`}
</CodeBlock></td>
</tr>
<tr>
<td style={{'text-align': 'center'}}>0x36</td>
<td style={{'text-align': 'center'}}>0x35</td>
<td style={{'text-align': 'center'}}><a id='isa-table-revert'/><Markdown>\[\`REVERT\`\](#isa-section-revert)</Markdown></td>
<td><Markdown>Halt execution within this context as `reverted`, optionally returning some data</Markdown></td>
<td><CodeBlock language="jsx">
Expand All @@ -518,7 +503,7 @@ halt`}
</CodeBlock></td>
</tr>
<tr>
<td style={{'text-align': 'center'}}>0x37</td>
<td style={{'text-align': 'center'}}>0x36</td>
<td style={{'text-align': 'center'}}><a id='isa-table-to_radix_le'/><Markdown>\[\`TORADIXLE\`\](#isa-section-to_radix_le)</Markdown></td>
<td><Markdown>Convert a word to an array of limbs in little-endian radix form</Markdown></td>
<td><Markdown>TBD: Storage of limbs and if T[dstOffset] is constrained to U8</Markdown></td>
Expand Down Expand Up @@ -1667,7 +1652,7 @@ chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=false)
nestedContext = deriveContext(context, instr.args, isStaticCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock>
Expand Down Expand Up @@ -1714,7 +1699,7 @@ chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=true, isDelegateCall=false)
nestedContext = deriveContext(context, instr.args, isStaticCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock>
Expand All @@ -1734,56 +1719,12 @@ T[retOffset:retOffset+retSize] = field`}

[![](/img/protocol-specs/public-vm/bit-formats/STATICCALL.png)](/img/protocol-specs/public-vm/bit-formats/STATICCALL.png)

### <a id='isa-section-delegatecall'/>`DELEGATECALL`
(UNIMPLEMENTED) Call into another contract, but keep the caller's `sender` and `storageAddress`

[See in table.](#isa-table-delegatecall)

- **Opcode**: 0x34
- **Category**: Control Flow - Contract Calls
- **Flags**:
- **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost 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 `{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)
- **argsSizeOffset**: memory offset for the 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**:
<CodeBlock language="jsx">
{`// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)`}
</CodeBlock>
- **Details**: Same as `CALL`, but `sender` and `storageAddress` remains
the same in the nested call as they were in the caller.
["Nested contract calls"](./nested-calls) provides a full explanation of this
instruction along with the shorthand used in the expression above.
The explanation includes details on charging gas for nested calls,
nested context derivation, world state tracing, and updating the parent context
after the nested call halts.
- **Tag checks**: `T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32`
- **Tag updates**:
<CodeBlock language="jsx">
{`T[successOffset] = u8
T[retOffset:retOffset+retSize] = field`}
</CodeBlock>
- **Bit-size**: 248


### <a id='isa-section-return'/>`RETURN`
Halt execution within this context (without revert), optionally returning some data

[See in table.](#isa-table-return)

- **Opcode**: 0x35
- **Opcode**: 0x34
- **Category**: Control Flow - Contract Calls
- **Flags**:
- **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`.
Expand All @@ -1805,7 +1746,7 @@ Halt execution within this context as `reverted`, optionally returning some data

[See in table.](#isa-table-revert)

- **Opcode**: 0x36
- **Opcode**: 0x35
- **Category**: Control Flow - Contract Calls
- **Flags**:
- **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`.
Expand All @@ -1828,7 +1769,7 @@ Convert a word to an array of limbs in little-endian radix form

[See in table.](#isa-table-to_radix_le)

- **Opcode**: 0x37
- **Opcode**: 0x36
- **Category**: Conversions
- **Flags**:
- **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`.
Expand Down
Loading

0 comments on commit e6577e5

Please sign in to comment.