-
Notifications
You must be signed in to change notification settings - Fork 305
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
9 changed files
with
441 additions
and
8 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
55 changes: 55 additions & 0 deletions
55
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,55 @@ | ||
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, | ||
storageAddress: 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, { | ||
address: 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, | ||
storageAddress: newAddress, | ||
isStaticCall: true, | ||
}); | ||
}); | ||
}); | ||
|
||
/** | ||
* Check all properties of one object are the same, except for the specified differentProperties | ||
*/ | ||
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
126 changes: 126 additions & 0 deletions
126
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,126 @@ | ||
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 { 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 journal: AvmJournal; | ||
|
||
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); | ||
journal = new AvmJournal(hostStorage); | ||
}); | ||
|
||
describe('Call', () => { | ||
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): gas not implemented | ||
it('Should execute a call correctly', async () => { | ||
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)]; | ||
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); | ||
|
||
const otherContextInstructions: [Opcode, any[]][] = [ | ||
// Place [1,2,3] into memory | ||
[Opcode.CALLDATACOPY, [/* value */ 0, /* copySize*/ argsSize, /* destOffset */ 0]], | ||
// Store 1 into slot 1 | ||
[Opcode.SSTORE, [/* slotOffset */ 0, /* dataOffset */ 0]], | ||
// Return [1,2] from memory | ||
[Opcode.RETURN, [/* retOffset */ 0, /* size */ 2]], | ||
]; | ||
|
||
const otherContextInstructionsBytecode = Buffer.concat( | ||
otherContextInstructions.map(([opcode, args]) => encodeToBytecode(opcode, args)), | ||
); | ||
jest | ||
.spyOn(journal.hostStorage.contractsDb, 'getBytecode') | ||
.mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); | ||
|
||
const instruction = new Call(gasOffset, addrOffset, argsOffset, argsSize, retOffset, retSize, successOffset); | ||
await instruction.execute(machineState, journal); | ||
|
||
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)]); | ||
|
||
// Check that the storage call has been merged into the parent journal | ||
const { storageWrites } = journal.flush(); | ||
expect(storageWrites.size).toEqual(1); | ||
const nestedContractWrites = storageWrites.get(addr); | ||
expect(nestedContractWrites).toBeDefined(); | ||
expect(nestedContractWrites!.get(args[0])).toEqual(args[0]); | ||
}); | ||
}); | ||
|
||
describe('Static Call', () => { | ||
it('Should fail if a static call attempts to touch storage', async () => { | ||
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)]; | ||
|
||
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); | ||
|
||
const otherContextInstructions: [Opcode, any[]][] = [ | ||
[Opcode.SET, [/* value */ 1, /* destOffset */ 1]], | ||
[Opcode.SSTORE, [/* slotOffset */ 1, /* dataOffset */ 0]], | ||
]; | ||
|
||
const otherContextInstructionsBytecode = Buffer.concat( | ||
otherContextInstructions.map(([opcode, args]) => encodeToBytecode(opcode, args)), | ||
); | ||
jest | ||
.spyOn(journal.hostStorage.contractsDb, 'getBytecode') | ||
.mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); | ||
|
||
const instruction = new Call(gasOffset, addrOffset, argsOffset, argsSize, retOffset, retSize, successOffset); | ||
await instruction.execute(machineState, journal); | ||
|
||
// No revert has occurred, but the nested execution has failed | ||
const successValue = machineState.readMemory(successOffset); | ||
expect(successValue).toEqual(new Fr(0n)); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.