Skip to content

Commit 028b259

Browse files
committed
fix mem ops tracking
1 parent 6a1d8ed commit 028b259

18 files changed

+123
-162
lines changed

yarn-project/simulator/src/avm/avm_memory_types.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ describe('MeteredTaggedMemory', () => {
9393
expect(() => mem.assert({ reads: 1, writes: 1 })).not.toThrow();
9494
});
9595

96-
// TODO(facundo): re-enable.
97-
it.skip(`Throws on failed stat assertion`, () => {
96+
it(`Throws on failed stat assertion`, () => {
9897
mem.get(10);
9998
expect(() => mem.assert({ reads: 1, writes: 1 })).toThrow();
10099
});

yarn-project/simulator/src/avm/avm_memory_types.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ export class TaggedMemory implements TaggedMemoryInterface {
413413
}
414414

415415
/** No-op. Implemented here for compatibility with the MeteredTaggedMemory. */
416-
public assert(_operations: Partial<MemoryOperations & { indirect: number }>) {}
416+
public assert(_operations: Partial<MemoryOperations & { addressing: Addressing }>) {}
417417
}
418418

419419
/** Tagged memory wrapper with metering for each memory read and write operation. */
@@ -435,12 +435,15 @@ export class MeteredTaggedMemory implements TaggedMemoryInterface {
435435
* Asserts that the exact number of memory operations have been performed.
436436
* Indirect represents the flags for indirect accesses: each bit set to one counts as an extra read.
437437
*/
438-
public assert(operations: Partial<MemoryOperations & { indirect: number }>) {
439-
return;
440-
441-
const { reads: expectedReads, writes: expectedWrites, indirect } = { reads: 0, writes: 0, ...operations };
442-
443-
const totalExpectedReads = expectedReads + Addressing.fromWire(indirect ?? 0).count(AddressingMode.INDIRECT);
438+
public assert(operations: Partial<MemoryOperations & { addressing: Addressing }>) {
439+
const {
440+
reads: expectedReads,
441+
writes: expectedWrites,
442+
addressing,
443+
} = { reads: 0, writes: 0, addressing: new Addressing([]), ...operations };
444+
445+
const totalExpectedReads =
446+
expectedReads + addressing.count(AddressingMode.INDIRECT) + addressing.count(AddressingMode.RELATIVE);
444447
const { reads: actualReads, writes: actualWrites } = this.reset();
445448
if (actualReads !== totalExpectedReads) {
446449
throw new InstructionExecutionError(

yarn-project/simulator/src/avm/opcodes/accrued_substate.ts

+21-33
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,11 @@ export class NoteHashExists extends Instruction {
2828
}
2929

3030
public async execute(context: AvmContext): Promise<void> {
31-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
3231
const memory = context.machineState.memory.track(this.type);
3332
context.machineState.consumeGas(this.gasCost());
3433
const operands = [this.noteHashOffset, this.leafIndexOffset, this.existsOffset];
35-
const [noteHashOffset, leafIndexOffset, existsOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(
36-
operands,
37-
memory,
38-
);
34+
const addressing = Addressing.fromWire(this.indirect, operands.length);
35+
const [noteHashOffset, leafIndexOffset, existsOffset] = addressing.resolve(operands, memory);
3936
memory.checkTags(TypeTag.FIELD, noteHashOffset, leafIndexOffset);
4037

4138
// Note that this instruction accepts any type in memory, and converts to Field.
@@ -49,7 +46,7 @@ export class NoteHashExists extends Instruction {
4946
);
5047
memory.set(existsOffset, exists ? new Uint8(1) : new Uint8(0));
5148

52-
memory.assert(memoryOperations);
49+
memory.assert({ reads: 2, writes: 1, addressing });
5350
context.machineState.incrementPc();
5451
}
5552
}
@@ -65,12 +62,12 @@ export class EmitNoteHash extends Instruction {
6562
}
6663

6764
public async execute(context: AvmContext): Promise<void> {
68-
const memoryOperations = { reads: 1, indirect: this.indirect };
6965
const memory = context.machineState.memory.track(this.type);
7066
context.machineState.consumeGas(this.gasCost());
7167

7268
const operands = [this.noteHashOffset];
73-
const [noteHashOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
69+
const addressing = Addressing.fromWire(this.indirect, operands.length);
70+
const [noteHashOffset] = addressing.resolve(operands, memory);
7471
memory.checkTag(TypeTag.FIELD, noteHashOffset);
7572

7673
if (context.environment.isStaticCall) {
@@ -80,7 +77,7 @@ export class EmitNoteHash extends Instruction {
8077
const noteHash = memory.get(noteHashOffset).toFr();
8178
context.persistableState.writeNoteHash(context.environment.storageAddress, noteHash);
8279

83-
memory.assert(memoryOperations);
80+
memory.assert({ reads: 1, addressing });
8481
context.machineState.incrementPc();
8582
}
8683
}
@@ -107,15 +104,12 @@ export class NullifierExists extends Instruction {
107104
}
108105

109106
public async execute(context: AvmContext): Promise<void> {
110-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
111107
const memory = context.machineState.memory.track(this.type);
112108
context.machineState.consumeGas(this.gasCost());
113109

114110
const operands = [this.nullifierOffset, this.addressOffset, this.existsOffset];
115-
const [nullifierOffset, addressOffset, existsOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(
116-
operands,
117-
memory,
118-
);
111+
const addressing = Addressing.fromWire(this.indirect, operands.length);
112+
const [nullifierOffset, addressOffset, existsOffset] = addressing.resolve(operands, memory);
119113
memory.checkTags(TypeTag.FIELD, nullifierOffset, addressOffset);
120114

121115
const nullifier = memory.get(nullifierOffset).toFr();
@@ -124,7 +118,7 @@ export class NullifierExists extends Instruction {
124118

125119
memory.set(existsOffset, exists ? new Uint8(1) : new Uint8(0));
126120

127-
memory.assert(memoryOperations);
121+
memory.assert({ reads: 2, writes: 1, addressing });
128122
context.machineState.incrementPc();
129123
}
130124
}
@@ -144,12 +138,12 @@ export class EmitNullifier extends Instruction {
144138
throw new StaticCallAlterationError();
145139
}
146140

147-
const memoryOperations = { reads: 1, indirect: this.indirect };
148141
const memory = context.machineState.memory.track(this.type);
149142
context.machineState.consumeGas(this.gasCost());
150143

151144
const operands = [this.nullifierOffset];
152-
const [nullifierOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
145+
const addressing = Addressing.fromWire(this.indirect, operands.length);
146+
const [nullifierOffset] = addressing.resolve(operands, memory);
153147
memory.checkTag(TypeTag.FIELD, nullifierOffset);
154148

155149
const nullifier = memory.get(nullifierOffset).toFr();
@@ -166,7 +160,7 @@ export class EmitNullifier extends Instruction {
166160
}
167161
}
168162

169-
memory.assert(memoryOperations);
163+
memory.assert({ reads: 1, addressing });
170164
context.machineState.incrementPc();
171165
}
172166
}
@@ -193,15 +187,12 @@ export class L1ToL2MessageExists extends Instruction {
193187
}
194188

195189
public async execute(context: AvmContext): Promise<void> {
196-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
197190
const memory = context.machineState.memory.track(this.type);
198191
context.machineState.consumeGas(this.gasCost());
199192

200193
const operands = [this.msgHashOffset, this.msgLeafIndexOffset, this.existsOffset];
201-
const [msgHashOffset, msgLeafIndexOffset, existsOffset] = Addressing.fromWire(
202-
this.indirect,
203-
operands.length,
204-
).resolve(operands, memory);
194+
const addressing = Addressing.fromWire(this.indirect, operands.length);
195+
const [msgHashOffset, msgLeafIndexOffset, existsOffset] = addressing.resolve(operands, memory);
205196
memory.checkTags(TypeTag.FIELD, msgHashOffset, msgLeafIndexOffset);
206197

207198
const msgHash = memory.get(msgHashOffset).toFr();
@@ -213,7 +204,7 @@ export class L1ToL2MessageExists extends Instruction {
213204
);
214205
memory.set(existsOffset, exists ? new Uint8(1) : new Uint8(0));
215206

216-
memory.assert(memoryOperations);
207+
memory.assert({ reads: 2, writes: 1, addressing });
217208
context.machineState.incrementPc();
218209
}
219210
}
@@ -236,19 +227,19 @@ export class EmitUnencryptedLog extends Instruction {
236227
const memory = context.machineState.memory.track(this.type);
237228

238229
const operands = [this.logOffset, this.logSizeOffset];
239-
const [logOffset, logSizeOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
230+
const addressing = Addressing.fromWire(this.indirect, operands.length);
231+
const [logOffset, logSizeOffset] = addressing.resolve(operands, memory);
240232
memory.checkTag(TypeTag.UINT32, logSizeOffset);
241233
const logSize = memory.get(logSizeOffset).toNumber();
242234
memory.checkTagsRange(TypeTag.FIELD, logOffset, logSize);
243235

244236
const contractAddress = context.environment.address;
245237

246-
const memoryOperations = { reads: 1 + logSize, indirect: this.indirect };
247238
context.machineState.consumeGas(this.gasCost(logSize));
248239
const log = memory.getSlice(logOffset, logSize).map(f => f.toFr());
249240
context.persistableState.writeUnencryptedLog(contractAddress, log);
250241

251-
memory.assert(memoryOperations);
242+
memory.assert({ reads: 1 + logSize, addressing });
252243
context.machineState.incrementPc();
253244
}
254245
}
@@ -268,21 +259,18 @@ export class SendL2ToL1Message extends Instruction {
268259
throw new StaticCallAlterationError();
269260
}
270261

271-
const memoryOperations = { reads: 2, indirect: this.indirect };
272262
const memory = context.machineState.memory.track(this.type);
273263
context.machineState.consumeGas(this.gasCost());
274264

275265
const operands = [this.recipientOffset, this.contentOffset];
276-
const [recipientOffset, contentOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(
277-
operands,
278-
memory,
279-
);
266+
const addressing = Addressing.fromWire(this.indirect, operands.length);
267+
const [recipientOffset, contentOffset] = addressing.resolve(operands, memory);
280268

281269
const recipient = memory.get(recipientOffset).toFr();
282270
const content = memory.get(contentOffset).toFr();
283271
context.persistableState.writeL2ToL1Message(recipient, content);
284272

285-
memory.assert(memoryOperations);
273+
memory.assert({ reads: 2, addressing });
286274
context.machineState.incrementPc();
287275
}
288276
}

yarn-project/simulator/src/avm/opcodes/arithmetic.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
66

77
export abstract class ThreeOperandArithmeticInstruction extends ThreeOperandInstruction {
88
public async execute(context: AvmContext): Promise<void> {
9-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
109
const memory = context.machineState.memory.track(this.type);
1110
context.machineState.consumeGas(this.gasCost());
1211

1312
const operands = [this.aOffset, this.bOffset, this.dstOffset];
14-
const [aOffset, bOffset, dstOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
13+
const addressing = Addressing.fromWire(this.indirect, operands.length);
14+
const [aOffset, bOffset, dstOffset] = addressing.resolve(operands, memory);
1515
memory.checkTags(this.inTag, aOffset, bOffset);
1616

1717
const a = memory.get(aOffset);
@@ -20,7 +20,7 @@ export abstract class ThreeOperandArithmeticInstruction extends ThreeOperandInst
2020
const dest = this.compute(a, b);
2121
memory.set(dstOffset, dest);
2222

23-
memory.assert(memoryOperations);
23+
memory.assert({ reads: 2, writes: 1, addressing });
2424
context.machineState.incrementPc();
2525
}
2626

yarn-project/simulator/src/avm/opcodes/bitwise.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
77

88
abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
99
public async execute(context: AvmContext): Promise<void> {
10-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
1110
const memory = context.machineState.memory.track(this.type);
1211
context.machineState.consumeGas(this.gasCost());
1312

1413
const operands = [this.aOffset, this.bOffset, this.dstOffset];
15-
const [aOffset, bOffset, dstOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
14+
const addressing = Addressing.fromWire(this.indirect, operands.length);
15+
const [aOffset, bOffset, dstOffset] = addressing.resolve(operands, memory);
1616
this.checkTags(memory, this.inTag, aOffset, bOffset);
1717

1818
const a = memory.getAs<IntegralValue>(aOffset);
@@ -21,7 +21,7 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
2121
const res = this.compute(a, b);
2222
memory.set(dstOffset, res);
2323

24-
memory.assert(memoryOperations);
24+
memory.assert({ reads: 2, writes: 1, addressing });
2525
context.machineState.incrementPc();
2626
}
2727

@@ -96,19 +96,19 @@ export class Not extends Instruction {
9696
}
9797

9898
public async execute(context: AvmContext): Promise<void> {
99-
const memoryOperations = { reads: 1, writes: 1, indirect: this.indirect };
10099
const memory = context.machineState.memory.track(this.type);
101100
context.machineState.consumeGas(this.gasCost());
102101

103102
const operands = [this.srcOffset, this.dstOffset];
104-
const [srcOffset, dstOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
103+
const addressing = Addressing.fromWire(this.indirect, operands.length);
104+
const [srcOffset, dstOffset] = addressing.resolve(operands, memory);
105105
TaggedMemory.checkIsIntegralTag(memory.getTag(srcOffset));
106106
const value = memory.getAs<IntegralValue>(srcOffset);
107107

108108
const res = value.not();
109109
memory.set(dstOffset, res);
110110

111-
memory.assert(memoryOperations);
111+
memory.assert({ reads: 1, writes: 1, addressing });
112112
context.machineState.incrementPc();
113113
}
114114
}

yarn-project/simulator/src/avm/opcodes/commitment.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ export class PedersenCommitment extends Instruction {
3434
const memory = context.machineState.memory.track(this.type);
3535

3636
const operands = [this.inputOffset, this.outputOffset, this.inputSizeOffset, this.genIndexOffset];
37-
const [inputOffset, outputOffset, inputSizeOffset, genIndexOffset] = Addressing.fromWire(
38-
this.indirect,
39-
operands.length,
40-
).resolve(operands, memory);
37+
const addressing = Addressing.fromWire(this.indirect, operands.length);
38+
const [inputOffset, outputOffset, inputSizeOffset, genIndexOffset] = addressing.resolve(operands, memory);
4139

4240
const inputSize = memory.get(inputSizeOffset).toNumber();
4341
memory.checkTag(TypeTag.UINT32, inputSizeOffset);
@@ -48,7 +46,6 @@ export class PedersenCommitment extends Instruction {
4846
const generatorIndex = memory.get(genIndexOffset).toNumber();
4947
memory.checkTag(TypeTag.UINT32, genIndexOffset);
5048

51-
const memoryOperations = { reads: inputSize + 2, writes: 3, indirect: this.indirect };
5249
context.machineState.consumeGas(this.gasCost(inputSize));
5350

5451
const inputBuffer: Buffer[] = inputs.map(input => input.toBuffer());
@@ -62,7 +59,7 @@ export class PedersenCommitment extends Instruction {
6259
memory.set(outputOffset + 1, commitment[1]); // Field typed
6360
memory.set(outputOffset + 2, new Uint8(isInfinity ? 1 : 0)); // U8 typed
6461

65-
memory.assert(memoryOperations);
62+
memory.assert({ reads: inputSize + 2, writes: 3, addressing });
6663
context.machineState.incrementPc();
6764
}
6865
}

yarn-project/simulator/src/avm/opcodes/comparators.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
66

77
abstract class ComparatorInstruction extends ThreeOperandInstruction {
88
public async execute(context: AvmContext): Promise<void> {
9-
const memoryOperations = { reads: 2, writes: 1, indirect: this.indirect };
109
const memory = context.machineState.memory.track(this.type);
1110
context.machineState.consumeGas(this.gasCost());
1211

1312
const operands = [this.aOffset, this.bOffset, this.dstOffset];
14-
const [aOffset, bOffset, dstOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
13+
const addressing = Addressing.fromWire(this.indirect, operands.length);
14+
const [aOffset, bOffset, dstOffset] = addressing.resolve(operands, memory);
1515
memory.checkTags(this.inTag, aOffset, bOffset);
1616

1717
const a = memory.get(aOffset);
@@ -20,7 +20,7 @@ abstract class ComparatorInstruction extends ThreeOperandInstruction {
2020
const dest = new Uint1(this.compare(a, b) ? 1 : 0);
2121
memory.set(dstOffset, dest);
2222

23-
memory.assert(memoryOperations);
23+
memory.assert({ reads: 2, writes: 1, addressing });
2424
context.machineState.incrementPc();
2525
}
2626

yarn-project/simulator/src/avm/opcodes/contract.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export class GetContractInstance extends Instruction {
2222
}
2323

2424
async execute(context: AvmContext): Promise<void> {
25-
const memoryOperations = { reads: 1, writes: 6, indirect: this.indirect };
2625
const memory = context.machineState.memory.track(this.type);
2726
context.machineState.consumeGas(this.gasCost());
2827

2928
const operands = [this.addressOffset, this.dstOffset];
30-
const [addressOffset, dstOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
29+
const addressing = Addressing.fromWire(this.indirect, operands.length);
30+
const [addressOffset, dstOffset] = addressing.resolve(operands, memory);
3131
memory.checkTag(TypeTag.FIELD, addressOffset);
3232

3333
const address = memory.get(addressOffset).toFr();
@@ -44,7 +44,7 @@ export class GetContractInstance extends Instruction {
4444

4545
memory.setSlice(dstOffset, data);
4646

47-
memory.assert(memoryOperations);
47+
memory.assert({ reads: 1, writes: 6, addressing });
4848
context.machineState.incrementPc();
4949
}
5050
}

yarn-project/simulator/src/avm/opcodes/control_flow.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,21 @@ export class JumpI extends Instruction {
4141
}
4242

4343
public async execute(context: AvmContext): Promise<void> {
44-
const memoryOperations = { reads: 1, indirect: this.indirect };
4544
const memory = context.machineState.memory.track(this.type);
4645
context.machineState.consumeGas(this.gasCost());
4746

4847
const operands = [this.condOffset];
49-
const [condOffset] = Addressing.fromWire(this.indirect, operands.length).resolve(operands, memory);
48+
const addressing = Addressing.fromWire(this.indirect, operands.length);
49+
const [condOffset] = addressing.resolve(operands, memory);
5050
const condition = memory.getAs<IntegralValue>(condOffset);
5151

52-
// TODO: reconsider this casting
5352
if (condition.toBigInt() == 0n) {
5453
context.machineState.incrementPc();
5554
} else {
5655
context.machineState.pc = this.loc;
5756
}
5857

59-
memory.assert(memoryOperations);
58+
memory.assert({ reads: 1, addressing });
6059
}
6160
}
6261

0 commit comments

Comments
 (0)