diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts index 123e0a0a064..a9911f8d82d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -30,7 +30,7 @@ describe('Arithmetic Instructions', () => { expect(actual).toEqual(expected); }); - it('Should wrap around on addition',async () => { + it('Should wrap around on addition', async () => { const a = new Field(1n); const b = new Field(Field.MODULUS - 1n); @@ -46,7 +46,7 @@ describe('Arithmetic Instructions', () => { }); describe('Sub', () => { - it('Should subtract correctly over field elements',async () => { + it('Should subtract correctly over field elements', async () => { const a = new Field(1n); const b = new Field(2n); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts index bb7831b8d5f..426542a2733 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -25,21 +25,21 @@ describe('Bitwise instructions', () => { expect(actual).toEqual(new Uint32(0b11100100010001000100n)); }); - it('Should OR correctly over integral types', () => { + it('Should OR correctly over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Or(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Or(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b11111110111011101111n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should XOR correctly over integral types',async () => { + it('Should XOR correctly over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); @@ -54,7 +54,7 @@ describe('Bitwise instructions', () => { }); describe('SHR', () => { - it('Should shift correctly 0 positions over integral types',async () => { + it('Should shift correctly 0 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); @@ -65,9 +65,10 @@ describe('Bitwise instructions', () => { const expected = a; const actual = machineState.memory.get(2); + expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types',async () => { + it('Should shift correctly 2 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); @@ -81,7 +82,7 @@ describe('Bitwise instructions', () => { expect(actual).toEqual(expected); }); - it('Should shift correctly 19 positions over integral types',async () => { + it('Should shift correctly 19 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(19n); @@ -111,7 +112,7 @@ describe('Bitwise instructions', () => { expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types',async () => { + it('Should shift correctly 2 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); @@ -139,7 +140,7 @@ describe('Bitwise instructions', () => { expect(actual).toEqual(expected); }); - it('Should truncate when shifting over bit size over integral types',async () => { + it('Should truncate when shifting over bit size over integral types', async () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(2n); @@ -154,7 +155,7 @@ describe('Bitwise instructions', () => { }); }); - it('Should NOT correctly over integral types',async () => { + it('Should NOT correctly over integral types', async () => { const a = new Uint16(0b0110010011100100n); machineState.memory.set(0, a); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts index 33919aba032..7a2f74df0e4 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts @@ -5,6 +5,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { HostStorage } from '../journal/host_storage.js'; import { AvmJournal } from '../journal/journal.js'; @@ -92,11 +93,11 @@ describe('External Calls', () => { describe('Static Call', () => { it('Should fail if a static call attempts to touch storage', async () => { const gasOffset = 0; - const gas = Fr.zero(); + const gas = new Field(0); const addrOffset = 1; - const addr = new Fr(123456n); + const addr = new Field(123456n); const argsOffset = 2; - const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; + const args = [new Field(1n), new Field(2n), new Field(3n)]; const argsSize = args.length; const retOffset = 8; @@ -108,8 +109,9 @@ describe('External Calls', () => { machineState.memory.setSlice(2, args); const otherContextInstructions: [Opcode, any[]][] = [ - [Opcode.SET, [/* value */ 1, /* destOffset */ 1]], - [Opcode.SSTORE, [/* slotOffset */ 1, /* dataOffset */ 0]], + // Place [1,2,3] into memory + [Opcode.CALLDATACOPY, [/*value=*/ 0, /*copySize=*/ argsSize, /*destOffset=*/ 0]], + [Opcode.SSTORE, [/*slotOffset*/ 1, /*dataOffset=*/ 0]], ]; const otherContextInstructionsBytecode = Buffer.concat( diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts index 38180dce916..fc98f6c780c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts @@ -2,9 +2,9 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmContext } from '../avm_context.js'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; -import { Field } from '../avm_memory_types.js'; export class Call extends Instruction { static type: string = 'CALL'; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts index 65cb6a64eba..de9af42972d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -18,7 +18,7 @@ describe('Memory instructions', () => { }); describe('SET', () => { - it('should correctly set value and tag (uninitialized)',async () => { + it('should correctly set value and tag (uninitialized)', async () => { await new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, journal); const actual = machineState.memory.get(1); @@ -150,7 +150,7 @@ describe('Memory instructions', () => { expect(tags).toEqual([TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128]); }); - it('Should cast between field elements',async () => { + it('Should cast between field elements', async () => { machineState.memory.set(0, new Field(12345678n)); await new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, journal); @@ -174,7 +174,7 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move field elements on different memory cells',async () => { + it('Should move field elements on different memory cells', async () => { machineState.memory.set(1, new Field(27)); await new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); @@ -187,7 +187,7 @@ describe('Memory instructions', () => { }); describe('CMOV', () => { - it('Should move A if COND is true, on different memory cells (integral condition)',async () => { + it('Should move A if COND is true, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(2)); // Condition @@ -203,7 +203,7 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)',async () => { + it('Should move B if COND is false, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(0)); // Condition @@ -219,12 +219,15 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move A if COND is true, on different memory cells (field condition)',async () => { + it('Should move A if COND is true, on different memory cells (field condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(1)); // Condition - await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -232,12 +235,15 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)',async () => { + it('Should move B if COND is false, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(0)); // Condition - await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -247,7 +253,7 @@ describe('Memory instructions', () => { }); describe('CALLDATACOPY', () => { - it('Writes nothing if size is 0',async () => { + it('Writes nothing if size is 0', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten @@ -258,7 +264,7 @@ describe('Memory instructions', () => { expect(actual).toEqual(new Uint16(12)); }); - it('Copies all calldata',async () => { + it('Copies all calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten @@ -269,7 +275,7 @@ describe('Memory instructions', () => { expect(actual).toEqual([new Field(1), new Field(2), new Field(3)]); }); - it('Copies slice of calldata',async () => { + it('Copies slice of calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 3ba63a633a7..0c8ada5b6cd 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -5,7 +5,7 @@ import { Instruction } from './instruction.js'; export class Set extends Instruction { static type: string = 'SET'; - static numberOfOperands = 2; + static numberOfOperands = 3; constructor(private value: bigint, private dstOffset: number, private dstTag: TypeTag) { super(); @@ -22,7 +22,7 @@ export class Set extends Instruction { export class Cast extends Instruction { static type: string = 'CAST'; - static numberOfOperands = 2; + static numberOfOperands = 3; constructor(private aOffset: number, private dstOffset: number, private dstTag: TypeTag) { super(); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts index aadbbbb69f1..47bc4433862 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { AvmJournal } from '../journal/journal.js'; import { SLoad, SStore, StaticCallStorageAlterError } from './storage.js'; @@ -21,23 +22,23 @@ describe('Storage Instructions', () => { }); it('Sstore should Write into storage', async () => { - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); await new SStore(0, 1).execute(machineState, journal); - expect(journal.writeStorage).toBeCalledWith(address, a, b); + expect(journal.writeStorage).toBeCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); it('Should not be able to write to storage in a static call', async () => { const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); machineState = new AvmMachineState(executionEnvironment); - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); @@ -51,15 +52,15 @@ describe('Storage Instructions', () => { const expectedResult = new Fr(1n); journal.readStorage.mockReturnValueOnce(Promise.resolve(expectedResult)); - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); await new SLoad(0, 1).execute(machineState, journal); - expect(journal.readStorage).toBeCalledWith(address, a); + expect(journal.readStorage).toBeCalledWith(address, new Fr(a.toBigInt())); const actual = machineState.memory.get(1); expect(actual).toEqual(expectedResult); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts index a452b0c422a..e8f078f7909 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -15,6 +15,10 @@ export class SStore extends Instruction { } async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + const slot = machineState.memory.get(this.slotOffset); const data = machineState.memory.get(this.dataOffset);