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 ce4e6165db4..438e7d9eadb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -6,6 +6,7 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { Field, TypeTag, Uint8, Uint16, Uint32, Uint64, Uint128 } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { AvmJournal } from '../journal/journal.js'; +import { InstructionExecutionError } from './instruction.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Memory instructions', () => { @@ -64,6 +65,27 @@ describe('Memory instructions', () => { expect(actual).toEqual(new Uint32(1234n)); expect(tag).toEqual(TypeTag.UINT32); }); + + it('should correctly set value and tag (truncating)', async () => { + await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*value=*/ 0x12345678n, /*offset=*/ 1).execute( + machineState, + journal, + ); + + const actual = machineState.memory.get(1); + const tag = machineState.memory.getTag(1); + + expect(actual).toEqual(new Uint16(0x5678)); + expect(tag).toEqual(TypeTag.UINT16); + }); + + it('should throw if tag is FIELD, UNINITIALIZED, INVALID', async () => { + for (const tag of [TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID]) { + await expect( + new Set(/*indirect=*/ 0, /*inTag=*/ tag, /*value=*/ 1234n, /*offset=*/ 1).execute(machineState, journal), + ).rejects.toThrow(InstructionExecutionError); + } + }); }); describe('CAST', () => { diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 31b05c95969..fd26f92060c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -2,7 +2,7 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { Field, TaggedMemory, TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/index.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; -import { Instruction } from './instruction.js'; +import { Instruction, InstructionExecutionError } from './instruction.js'; import { TwoOperandInstruction } from './instruction_impl.js'; export class Set extends Instruction { @@ -22,8 +22,12 @@ export class Set extends Instruction { } async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const res = TaggedMemory.integralFromTag(this.value, this.inTag); + // Per the YP, the tag cannot be a field. + if ([TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID].includes(this.inTag)) { + throw new InstructionExecutionError(`Invalid tag ${TypeTag[this.inTag]} for SET.`); + } + const res = TaggedMemory.integralFromTag(this.value, this.inTag); machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState);