-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
276 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { initExecutionEnvironment } from './fixtures/index.js'; | ||
|
||
describe('Execution Environment', () => { | ||
it('New call should fork execution environment correctly', () => { | ||
const newAddress = new Fr(123456n); | ||
|
||
const executionEnvironment = initExecutionEnvironment(); | ||
const newExecutionEnvironment = executionEnvironment.newCall(newAddress); | ||
|
||
allTheSameExcept(executionEnvironment, newExecutionEnvironment, { address: newAddress }); | ||
}); | ||
|
||
it('New delegate call should fork execution environment correctly', () => { | ||
const newAddress = new Fr(123456n); | ||
|
||
const executionEnvironment = initExecutionEnvironment(); | ||
const newExecutionEnvironment = executionEnvironment.newDelegateCall(newAddress); | ||
|
||
allTheSameExcept(executionEnvironment, newExecutionEnvironment, { | ||
storageAddress: newAddress, | ||
isDelegateCall: true, | ||
}); | ||
}); | ||
|
||
it('New static call call should fork execution environment correctly', () => { | ||
const newAddress = new Fr(123456n); | ||
|
||
const executionEnvironment = initExecutionEnvironment(); | ||
const newExecutionEnvironment = executionEnvironment.newStaticCall(newAddress); | ||
|
||
allTheSameExcept(executionEnvironment, newExecutionEnvironment, { address: newAddress, isStaticCall: true }); | ||
}); | ||
}); | ||
|
||
/** | ||
* Check all properties of one object are the same, except for the specified differentProperties | ||
* TODO: maybe move this into some foundation test utilities file? | ||
*/ | ||
function allTheSameExcept(referenceObject: any, comparingObject: any, differentProperties: Record<string, any>): void { | ||
for (const key in referenceObject) { | ||
if (Object.keys(differentProperties).includes(key)) { | ||
expect(comparingObject[key]).toEqual(differentProperties[key]); | ||
} else { | ||
expect(comparingObject[key]).toEqual(referenceObject[key]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { BlockHeader } from '@aztec/circuits.js'; | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { jest } from '@jest/globals'; | ||
import { MockProxy, mock } from 'jest-mock-extended'; | ||
|
||
import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; | ||
import { AvmMachineState } from '../avm_machine_state.js'; | ||
import { AvmStateManager } from '../avm_state_manager.js'; | ||
import { initExecutionEnvironment } from '../fixtures/index.js'; | ||
import { HostStorage } from '../journal/host_storage.js'; | ||
import { AvmJournal } from '../journal/journal.js'; | ||
import { encodeToBytecode } from './encode_to_bytecode.js'; | ||
import { Call } from './external_calls.js'; | ||
import { Opcode } from './opcodes.js'; | ||
|
||
describe('External Calls', () => { | ||
let machineState: AvmMachineState; | ||
let stateManager: AvmStateManager; | ||
|
||
let contractsDb: MockProxy<PublicContractsDB>; | ||
|
||
beforeEach(() => { | ||
machineState = new AvmMachineState([], initExecutionEnvironment()); | ||
|
||
contractsDb = mock<PublicContractsDB>(); | ||
|
||
const commitmentsDb = mock<CommitmentsDB>(); | ||
const publicStateDb = mock<PublicStateDB>(); | ||
const hostStorage = new HostStorage(publicStateDb, contractsDb, commitmentsDb); | ||
const journal = new AvmJournal(hostStorage); | ||
const blockHeader = BlockHeader.empty(); | ||
|
||
stateManager = new AvmStateManager(blockHeader, journal); | ||
}); | ||
|
||
describe('Call', () => { | ||
it('Should create a new call context correctly', async () => { | ||
// TODO: gas not implemented | ||
// prettier-ignore-start | ||
// mem index | value | ||
const gasOffset = 0; | ||
const gas = Fr.zero(); | ||
const addrOffset = 1; | ||
const addr = new Fr(123456n); | ||
const argsOffset = 2; | ||
const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; | ||
// prettier-ignore-end | ||
|
||
const argsSize = args.length; | ||
const retOffset = 8; | ||
const retSize = 2; | ||
const successOffset = 7; | ||
|
||
machineState.writeMemory(0, gas); | ||
machineState.writeMemory(1, addr); | ||
machineState.writeMemoryChunk(2, args); | ||
|
||
// TODO: mock the call that is made -> set the bytecode to be a return of two values | ||
const otherContextInstructions: [Opcode, any[]][] = [ | ||
[Opcode.SET, [/* value */ 1, /* destOffset */ 0]], | ||
[Opcode.SET, [/* value */ 2, /* destOffset */ 1]], | ||
[Opcode.RETURN, [/* retOffset */ 0, /* size */ 2]], | ||
]; | ||
|
||
const otherContextInstructionsBytecode = Buffer.concat( | ||
otherContextInstructions.map(([opcode, args]) => encodeToBytecode(opcode, args)), | ||
); | ||
jest | ||
.spyOn(stateManager.journal.hostStorage.contractsDb, 'getBytecode') | ||
.mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); | ||
|
||
const instruction = new Call(gasOffset, addrOffset, argsOffset, argsSize, retOffset, retSize, successOffset); | ||
await instruction.execute(machineState, stateManager); | ||
|
||
const successValue = machineState.readMemory(successOffset); | ||
expect(successValue).toEqual(new Fr(1n)); | ||
|
||
const retValue = machineState.readMemoryChunk(retOffset, retSize); | ||
expect(retValue).toEqual([new Fr(1n), new Fr(2n)]); | ||
}); | ||
}); | ||
}); |
52 changes: 52 additions & 0 deletions
52
yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { AvmContext } from '../avm_context.js'; | ||
import { AvmMachineState } from '../avm_machine_state.js'; | ||
import { AvmStateManager } from '../avm_state_manager.js'; | ||
import { Instruction } from './instruction.js'; | ||
|
||
/** - */ | ||
export class Call extends Instruction { | ||
static type: string = 'CALL'; | ||
static numberOfOperands = 7; | ||
|
||
constructor( | ||
private /* Unused due to no formal gas implementation at this moment */ _gasOffset: number, | ||
private addrOffset: number, | ||
private argsOffset: number, | ||
private argSize: number, | ||
private retOffset: number, | ||
private retSize: number, | ||
private successOffset: number, | ||
) { | ||
super(); | ||
} | ||
|
||
// TODO: there is no concept of remaining / available gas at this moment | ||
async execute(machineState: AvmMachineState, stateManager: AvmStateManager): Promise<void> { | ||
// This instruction will need to create another instance of the AVM with: | ||
// - a forked State Manager | ||
// - the same execution environment variables | ||
// - a fresh memory instance | ||
|
||
const callAddress = machineState.readMemory(this.addrOffset); | ||
// TODO: check that we can assume that this memory chunk will be field elements | ||
const calldata = machineState.readMemoryChunk(this.argsOffset, this.argSize); | ||
|
||
// TODO: could this be consolidated within an AVMContext static member? | ||
const newExecutionEnvironment = machineState.executionEnvironment.newCall(callAddress); | ||
const avmContext = AvmContext.newWithForkedState(newExecutionEnvironment, stateManager); | ||
|
||
const returnObject = await avmContext.call(calldata); | ||
const success = !returnObject.reverted; | ||
|
||
// We only take as much data as was specified in the return size -> TODO: should we be reverting here | ||
const returnData = returnObject.output.slice(0, this.retSize); | ||
|
||
// Write our return data into memory | ||
machineState.writeMemory(this.successOffset, new Fr(success)); | ||
machineState.writeMemoryChunk(this.retOffset, returnData); | ||
|
||
this.incrementPc(machineState); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters