From 013891fc3a65066a315652ad0ac41a9622b59573 Mon Sep 17 00:00:00 2001 From: Facundo Date: Fri, 2 Feb 2024 11:12:35 +0000 Subject: [PATCH] feat(avm): complete SET instruction (#4378) This pull request completes the implementation of the SET instruction and adds handling for invalid tags. It also includes necessary tests for the new functionality. SET takes the given u128, casts it to the provided inTag type, and sets the memory. Ref: #4267, #4271. --- .../src/avm/opcodes/memory.test.ts | 22 +++++++++++++++++++ .../acir-simulator/src/avm/opcodes/memory.ts | 8 +++++-- 2 files changed, 28 insertions(+), 2 deletions(-) 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);